# Lift
Source: https://docs.arcyai.com/lift
{/* screenshot: Lift, headline with the four metric cards and one funnel card below */}
**Lift** compares users who ran a flow against users who reached the same starting point and
did not run it, for every flow in the selected environment. There is nothing to switch on: a
flow appears here once its steps can be measured.
## Before you start
You need at least one flow with steps. Build one on [Flows](/autopilot/flows); the flow
builder tells you when a flow cannot be measured and what to change. Users must reach the
flow's first step in your Product before either group has anyone in it.
The **Revenue involved** card reads `plan_value` from `identify()`. Until your Product sends it,
the card reads **Not sent** rather than a zero. See [Attributes](/autopilot/attributes).
## What it changes
Nothing on Lift changes the widget. The page reads the environment picked in the sidebar.
The headline pools every measurable flow into one relative figure, for example "+38% more
users finish", with the raw point difference and both finish rates underneath so you can check
it. Four cards follow: **Finish rate**, **Time to finish**, **Revenue involved** and
**Furthest step reached**, each with the without-ARCY value under it. The line beneath says
how many of your flows the number covers: a flow with too little data is left out rather than
counted as zero. The page stamps when the number was worked out, and **Refresh** recomputes it.
Both groups count as finished the same way, by reaching the flow's last step in your Product
however they got there, including when ARCY did the step for them. A step still counts when
the button's text or position has changed since you picked it. Users choose whether to use ARCY, so this is a comparison between two
groups of people and not a controlled test. The page says so under the headline and inside
every report.
One card per flow follows, most-reached first. Each draws the funnel twice, **Without ARCY**
and **With ARCY**, one row per step on a shared scale, with the drop between rows written as a
percentage. The card ends with both finish rates and that flow's own **Lift**. The lift figure
stays hidden as **Waiting for more users** until both groups have 30 finished users; the card
says how many each side has so far. Every user who reached the flow is in one of the two
columns: **With ARCY** holds the users who ran this flow, **Without ARCY** holds everyone else,
whether or not they used ARCY for something else.
Each card carries a timeline of what happened to that flow: **ARCY installed**, **Published**,
**Taken down**, **Steps changed**, **Content changed**.
**Write the report** asks ARCY to describe one flow's comparison in plain language from the
numbers on the card, with a recommended next step. **Copy report** puts the text, both rates,
both sample sizes and the method note on your clipboard.
## When it goes wrong
**The page shows No flows to measure yet.** No flow in this environment has measurable steps.
Open [Flows](/autopilot/flows) and add steps, or fix the step the builder names.
**A flow you published is missing.** Its last step is a navigate to another site, or a step
with no target yet, and ARCY cannot observe either. The builder names the step. Add a click, a
fill or a navigate step after it and the funnel appears.
**A card says No users have reached this flow yet.** Nobody has arrived at its first step in
this environment. Check the flow's page URL and audience on [Flows](/autopilot/flows).
## See also
- [Flows](/autopilot/flows)
- [Pulse](/pulse)
- [Attributes](/autopilot/attributes)
---
# Pulse
Source: https://docs.arcyai.com/pulse
{/* screenshot: Pulse, Insights and Conversations sections with one conversation open */}
**Pulse** is where you read what happened in the selected environment: the insights ARCY
found, every conversation, the questions it could not answer, and how each flow is doing.
## Before you start
Pulse fills as traffic arrives. Until the install is confirmed on
[Installation](/settings/installation), every section offers that page instead of numbers.
**Conversations** and the questions in the content gap table need **Store conversations**
turned on for the Product. With it off, the conversation list stays empty and the content gap
table keeps its counts but shows **Question not stored**. See [Consent](/settings/consent).
## What it changes
Nothing on Pulse changes the widget. Everything is read from the environment picked in the
sidebar, so a development test session never lands in production numbers.
**Insights** are short findings, each with a number and a button that opens the place it
points at. A **Best guess:** line is a possible cause, not a measured one. Revenue-ranked
findings need `plan_value` and `plan_cycle` sent through `identify()`, and the section says so
until they arrive. See [Attributes](/autopilot/attributes).
**Conversations** lists every conversation, searchable by message text, with how many answers
the visitor rated good or bad. Open one to read it in full, with **What the agent did** above
each answer: the searches it ran, the pages it read, whether it handed off.
**Content gap** is the table of questions ARCY could not answer from your material: the
question, how often it was asked, when it was last seen, and the agent's note of what it looked
for. One row is one question however it was phrased. Click a row to filter Conversations to
the conversations behind it. Close a gap on [Train](/autopilot/train).
**Flows** covers the flows published in this environment plus any flow that ran inside the
chosen date range: the last 7, 30 or 90 days, or any two dates. The range drives the three
tiles (**Runs started**, **Completion rate**, **Live flows**), both charts and the table.
Drafts stay out of the numbers. Every run ends in exactly one outcome:
| Outcome | Meaning |
|---|---|
| **Completed** | The person reached the last step, even if a step failed on the way. The error still counts in **Errors**. |
| **Failed** | A step errored and the run never finished. |
| **Dismissed** | The person closed the flow. |
| **Left unfinished** | No ending and no activity for 30 minutes. |
| **In progress** | The run is still open. |
**How every run ended** stacks those outcomes per day. **Runs by flow** draws one bar per flow
for the ten busiest and rolls the rest into **Other flows**. Click a bar or a flow name to open
that flow's own page: the last 30 days of runs, the step funnel with its **Drop-off** step
marked, **Errors**, **How runs started**, **Agent suggestions** and **Self-heal history**.
Flows that are not counted are listed under the table as **Not tracked in this environment**,
with the reason. **Start tracking** publishes the flow here; a flow with no steps offers **Open
in builder** instead. Only an organization admin sees either button.
## When it goes wrong
**The Flows section says the range went past the scan limit.** The numbers cover only the most
recent events. Pick a shorter date range.
**A flow shows Few users so far.** Its weakest step is not highlighted until enough people
have run it.
**The content gap table says the Product has no training content.** ARCY has nothing to
answer from, so every question lands here. Add a source on [Train](/autopilot/train).
## See also
- [Flows](/autopilot/flows)
- [Lift](/lift)
- [Train](/autopilot/train)
---
# Quickstart
Source: https://docs.arcyai.com/quickstart
Your environment's snippets, with the real token already filled in, are in the dashboard under
**Settings > Installation**. That page also carries the go-live steps for the environment you
have selected; this page is the code. No account yet? Start with
[Create account](/getting-started/create-account).
Everything else ARCY does is configured in the dashboard, not in code. There is no config
file and nothing to redeploy when you change a setting.
## Required steps
### Add arcy.js to your Product
Pick your framework. Every path does the same two things: `init()` starts ARCY with your
environment token, and `identify()` tells ARCY who the current user is.
React
Next.js
Vue
Nuxt
Svelte
Angular
Astro
React Router
HTML
Install the package:
Call ARCY once, where your Product starts. In a Vite or Create React App project that is your
root component:
Install the package:
arcy.js runs in the browser only, so keep the call in a client component.
App Router
Pages Router
Add one client component and render it in your root layout:
```tsx title="app/layout.tsx"
import { ARCY } from "./arcy"
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
{children}
)
}
```
Call ARCY once in `_app.tsx`, the component that wraps every page:
Install the package:
Call ARCY where you create the Vue application:
Install the package:
Add a client plugin. The `.client` in the file name keeps it out of the server render:
Install the package:
Call ARCY from your root layout, inside `onMount` so it runs in the browser only:
Install the package:
Call ARCY from your root component:
Install the package:
Add a script to the layout every page uses. Astro bundles it and runs it in the browser:
Install the package:
Call ARCY from your root route, inside an effect so it runs after hydration:
No package to install. Use this path when you have no bundler, or when you install through a
tag manager. Paste the block from the Installation page into your HTML just before the
closing body tag. The first script is ARCY's loader: it already carries your environment's
token, loads asynchronously, queues calls made before it finishes, and never needs editing.
The second script is yours.
Never put the HTML snippet and the package on the same page. Pick one.
The token in `init()` belongs to one environment. It is public and appears in your page
source, so it is safe to ship. Each environment has its own token; switch environments in the
dashboard sidebar to get another one.
### Replace the placeholders
Only the Your own auth tab leaves placeholders behind. Clerk, Auth.js, Supabase and
Firebase read the user out of their own session, so if you picked one of those go straight to
the next step.
Swap each placeholder for a real, dynamic value from your session code, or every visitor
arrives as the same person:
| Placeholder | Meaning |
| -------------------- | ---------------------------------------------------------------- |
| `USER_ID` | The signed-in user's ID in your own database |
| `USER_FIRST_NAME` | The user's first name, as a dynamic value |
| `USER_LAST_NAME` | The user's last name, as a dynamic value |
| `USER_EMAIL` | The user's real email, as a dynamic value |
| `USER_SIGNED_UP_AT` | When the user signed up. ISO 8601, e.g. `2019-12-11T12:34:56Z` |
### Verify the installation
Open the real page in a browser, then click Verify installation on
[Settings > Installation](/settings/installation). It confirms traffic is arriving from the
selected environment and names the failure when none is. Each verdict has a fix on
[Troubleshooting](/troubleshooting).
## Optional steps
### Add custom attributes
The attributes you pass to `identify()` decide what ARCY can work out. Pass `plan_value` and
`plan_cycle` for revenue at risk and `organization_id` for per-account totals. Every key must
be declared under [Autopilot > Attributes](/autopilot/attributes) before you send it; an
undeclared key is dropped, never stored.
### Sign user ids for identity verification
Without it, anyone can type `arcy.identify("someone-elses-id")` into a browser console and read
that person's conversations. Your server signs each user id with the environment's Secret, and
the browser passes the signature along. Where the Secret is shown and what replacing it does is
on [Environments](/autopilot/environments).
The Secret is a server-side credential. Never put it in front-end code, a build variable that
reaches the browser, a mobile binary, or a repository. Anyone holding it can sign any user id.
The signature is HMAC-SHA256 of the user id, keyed with the Secret, hex encoded. It covers the
user id only, not the attributes, and it is the recipe Intercom and Segment use. Sign the exact
string you pass to `identify()`: if your ids are integers and you call
`arcy.identify(String(user.id))`, sign `String(user.id)`.
Node.js
Python
Ruby
PHP
```js
import { createHmac } from "node:crypto"
const userHash = createHmac("sha256", process.env.ARCY_SECRET)
.update(String(user.id))
.digest("hex")
```
```python
import hashlib, hmac, os
user_hash = hmac.new(
os.environ["ARCY_SECRET"].encode("utf-8"),
str(user.id).encode("utf-8"),
hashlib.sha256,
).hexdigest()
```
```ruby
user_hash = OpenSSL::HMAC.hexdigest("SHA256", ENV["ARCY_SECRET"], user.id.to_s)
```
```php
$userHash = hash_hmac('sha256', (string) $userId, getenv('ARCY_SECRET'));
```
Pass the result in the third argument of `identify()`:
```js
arcy.identify("USER_ID", {
user_first_name: "USER_FIRST_NAME",
user_email: "USER_EMAIL",
}, {
userHash: "USER_HASH", // computed on your server, never in the browser
})
```
`identifyAnonymous()` and `updateUser()` take no hash. Until you switch
Require identity verification on, signatures are checked and recorded but nothing is turned
away. Watch the checks on [Identity verification](/autopilot/identity-verification) and switch
it on once they pass.
### Serve visitors who are not signed in
For public pages, call `arcy.identifyAnonymous()` instead of `identify()`. The visitor gets an
id in a first-party cookie on your domain, so a returning visitor is the same person across
sessions and subdomains. Anonymous chats draw on the same allowance as identified ones; cap
them under [Settings > Limits](/settings/limits).
## Installing through a tag manager
The HTML path works unchanged in Google Tag Manager and similar tools:
1. Create a Custom HTML tag.
2. Paste the full HTML snippet from the Installation page, both scripts included.
3. Trigger it on all pages and publish the container.
The loader ignores a second initialization, so a tag that fires twice does no harm. Electron
and self-hosting the loader are not supported; an Electron renderer can use the npm path.
## See also
- [Reference](/reference)
- [Installation](/settings/installation)
- [Troubleshooting](/troubleshooting)
---
# Reference
Source: https://docs.arcyai.com/reference
arcy.js has one entry point, `arcy.init(token)`, identical in every framework and on both
install paths (npm and the HTML snippet). Code sets only what has to be known before the
dashboard can be reached: the reply language, whether the panel opens on load, the content
locale and where requests go. The agent's persona, its Sources, its flows, its limits and its
translations are all configured in the dashboard. The token is on **Settings > Installation**;
the install itself is on the [Quickstart](/quickstart).
No call throws and no promise rejects. A misuse produces a `console.warn` prefixed `[arcy]` and
does nothing.
## `init(token, options?)`
```ts
init(token: string, options?: ArcyOptions): Promise
```
Mounts ARCY for one environment. `token` is that environment's public Token. A second call on
the same page, or a call with no token, is ignored with a warning.
`options` accepts exactly four keys. Any other key is ignored with a warning naming it.
```ts
interface ArcyOptions {
locale?: string
defaultOpen?: boolean
contentLocale?: string
apiBase?: string
}
```
| Option | Value | Effect |
| --- | --- | --- |
| `locale` | `"en"` or `"tr"` | The language the agent replies in by default. Does not choose translated content. |
| `defaultOpen` | `true` or `false` | Opens the chat panel on load. Unset, the panel stays closed. |
| `contentLocale` | `"en-US"` or `"tr-TR"` | Which locale's translated content is served when you know the visitor's region before they identify. Not derived from `locale`. See [Localization](/autopilot/localization). |
| `apiBase` | An origin, or an origin with a path prefix, no trailing slash | Where every request, upload and font goes instead of `https://api.arcyai.com`. For pages under a Content Security Policy that allow no outside origin. See [Troubleshooting](/troubleshooting#content-security-policy). |
```ts
import arcy from "arcy.js"
arcy.init("YOUR_ENVIRONMENT_TOKEN", { locale: "tr", contentLocale: "tr-TR" })
```
## `identify(userId, attributes?, options?)`
```ts
identify(userId: string, attributes?: AttributesInput, options?: IdentifyOptions): Promise
```
Tells ARCY who the current user is. `userId` must be a non-empty string; anything else is
ignored with a warning. `attributes` is a flat object of keys you have declared under
[Autopilot > Attributes](/autopilot/attributes). Each value is a string, number, boolean,
`null`, or an array of strings; a value of any other shape is dropped with a warning naming
the key.
Three cases stay distinct: a key you leave out is not touched, `undefined` is the same thing
spelled in JavaScript, and `null` clears the stored value. That lets you pass an optional field
from your auth provider straight through:
```ts
arcy.identify(user.id, {
email: user.primaryEmailAddress?.emailAddress,
plan_value: 249,
plan_cycle: "monthly",
})
```
`options.userHash` carries the identity-verification signature your server computed. The
recipe is on the [Quickstart](/quickstart#sign-user-ids-for-identity-verification). A
`userHash` that is not a string is ignored with a warning.
## `identifyAnonymous(attributes?)`
```ts
identifyAnonymous(attributes?: AttributesInput): Promise
```
For pages with no signed-in user. Reuses or mints an id kept in a first-party cookie on your
domain, so a returning visitor is one person across sessions and subdomains, and the activity
before a sign-up joins the account after it. Anonymous chats count against the same allowance
as identified ones; the caps are on [Limits](/settings/limits).
## `updateUser(attributes?)`
```ts
updateUser(attributes?: AttributesInput): Promise
```
Merges attributes into the current identity without changing who it is. Takes no `userHash`:
it inherits the verification state of the `identify()` call before it. Called before any
`identify()` or `identifyAnonymous()`, it sends nothing.
## `reset()`
```ts
reset(): void
```
Clears the current identity and starts a fresh anonymous id. Call it from your sign-out
handler so two people on one browser are never merged.
## `consent(granted)`
```ts
consent(granted: boolean): void
```
Records the visitor's answer to your cookie policy. Call it with `true` from your banner's
Accept handler and `false` from its Reject handler, any time after `init()`. `false` deletes
every cookie and key ARCY wrote on the device. What each answer stops, and how the chat asks
again, is on [Consent](/settings/consent).
## `consentState()`
```ts
consentState(): "granted" | "refused" | null
```
The visitor's current answer on this device. `null` means no answer yet, so your banner should
show itself.
## `onConsent(handler)`
```ts
onConsent(handler: (granted: boolean) => void): () => void
```
Fires on every change from any source, including an Accept inside the chat, and returns an
unsubscribe function. Update Google Consent Mode, your CMP or your own flag here. Wiring
examples are on [Consent](/settings/consent).
## `on(event, handler)`
```ts
on(event: "ready" | "open" | "close", handler: () => void): () => void
```
Subscribes to a widget lifecycle event and returns an unsubscribe function. `ready` fires once
`init()` has configured the session; `open` and `close` fire when the panel's visibility
changes. Callable before `init()`.
## `open()` and `close()`
```ts
open(): void
close(): void
```
Open or close the chat panel from your own code. Both are synchronous.
## `VERSION`
```ts
arcy.VERSION // "0.1.7"
```
The installed arcy.js version, for a support ticket. Before 1.0 a breaking change can ship
without a major version bump, so pin the version you tested. From 1.0 on, a breaking change
means a new major version and advance notice.
## See also
- [Quickstart](/quickstart)
- [Troubleshooting](/troubleshooting)
- [Consent](/settings/consent)
---
# Troubleshooting
Source: https://docs.arcyai.com/troubleshooting
arcy.js never throws into your Product. Every problem it hits becomes a `console.warn`
prefixed `[arcy]`, so open the browser console first: the line there names the problem.
The sections are numbered so you can point at one, and the numbers match on the Turkish page.
## 1. The widget does not show up [#widget-not-showing]
Look for this first:
```
[arcy] Failed to load. ARCY is disabled.
```
The script itself never loaded. An ad blocker, your Content Security Policy
([section 2](#content-security-policy)), or a page that navigated away before the script
finished are the usual causes.
Without that line, arcy.js loaded but did not mount. Two messages say why:
```
[arcy] The page has no to mount into yet. The widget will not render.
```
`init()` ran before the body existed, usually a script in the head without `defer` or `async`.
Move the script tag to the end of the body, or call `arcy.init()` after the DOM is ready.
```
[arcy] This ARCY surface is already on this page. Ignoring the second mount.
[arcy] Another copy of ARCY is already on this page. Ignoring this one.
```
The snippet is installed twice: the npm path and the HTML path on one page, or the HTML
snippet pasted into both a layout and a tag manager. Keep
[one install path](/quickstart#required-steps) and remove the other.
## 2. Your Content Security Policy is blocking the widget [#content-security-policy]
The widget reports the whole fix once, the first time your policy blocks something of ours:
```
[arcy] This page's Content-Security-Policy is blocking part of the ARCY widget.
Add these to the policy your app sends:
connect-src https://api.arcyai.com
font-src https://api.arcyai.com
img-src https://api.arcyai.com blob:
style-src 'unsafe-inline', or a nonce on the script that loads ARCY
```
On the HTML snippet path the list also carries `script-src https://cdn.arcyai.com`, because
the snippet is a script tag pointing there. On the npm path the chat panel, the flow engine and
the picker are part of your own bundle and need nothing.
A directive you did not write is not enforced, and nothing falls back except through
`default-src`. So a policy with no `default-src` needs nothing added, and a policy with one
needs the lines above. Your full policy is the `Content-Security-Policy` response header on the
document request in the browser's network tab.
The `blob:` in `img-src` is what lets a visitor see the image they attached before they send it.
### Where to put it
Next.js
Nuxt
SvelteKit
Astro
React Router
Express
Static
If you already build the policy in `middleware.ts`, add the directives there. Otherwise:
```js
// next.config.js
const csp = [
"connect-src 'self' https://api.arcyai.com",
"font-src 'self' https://api.arcyai.com",
"img-src 'self' blob: https://api.arcyai.com",
].join("; ")
module.exports = {
async headers() {
return [
{
source: "/:path*",
headers: [{ key: "Content-Security-Policy", value: csp }],
},
]
},
}
```
```ts
// nuxt.config.ts
export default defineNuxtConfig({
routeRules: {
"/**": {
headers: {
"Content-Security-Policy": [
"connect-src 'self' https://api.arcyai.com",
"font-src 'self' https://api.arcyai.com",
"img-src 'self' blob: https://api.arcyai.com",
].join("; "),
},
},
},
})
```
SvelteKit generates the policy itself, so add the directives to the config:
```js
// svelte.config.js
export default {
kit: {
csp: {
directives: {
"connect-src": ["self", "https://api.arcyai.com"],
"font-src": ["self", "https://api.arcyai.com"],
"img-src": ["self", "blob:", "https://api.arcyai.com"],
},
},
},
}
```
```ts
// src/middleware.ts
export const onRequest = async (context, next) => {
const response = await next()
response.headers.set(
"Content-Security-Policy",
[
"connect-src 'self' https://api.arcyai.com",
"font-src 'self' https://api.arcyai.com",
"img-src 'self' blob: https://api.arcyai.com",
].join("; "),
)
return response
}
```
```ts
// app/entry.server.tsx
responseHeaders.set(
"Content-Security-Policy",
[
"connect-src 'self' https://api.arcyai.com",
"font-src 'self' https://api.arcyai.com",
"img-src 'self' blob: https://api.arcyai.com",
].join("; "),
)
```
```js
app.use(
helmet.contentSecurityPolicy({
directives: {
connectSrc: ["'self'", "https://api.arcyai.com"],
fontSrc: ["'self'", "https://api.arcyai.com"],
imgSrc: ["'self'", "blob:", "https://api.arcyai.com"],
},
}),
)
```
If you cannot set a header, set the policy in a `` tag in the head, before every script on
the page:
```html
```
### The panel renders unstyled
The widget adds its own style elements. With `style-src 'unsafe-inline'` there is nothing to
do. With a nonce there is nothing to do either: the widget reads the nonce off the script that
loaded it and stamps it on everything it injects. If the panel is unstyled and the console says
nothing, this is where to look.
### To allow no outside origin
Rewrite a path on your own domain to our API and pass it as `apiBase`. Requests, uploads and
fonts then all come from your own origin.
```js
// next.config.js
async rewrites() {
return [{ source: "/_arcy/:path*", destination: "https://api.arcyai.com/:path*" }]
}
```
```js
arcy.init("YOUR_ENVIRONMENT_TOKEN", { apiBase: "/_arcy" })
```
That closes everything on the npm path. The HTML snippet path still needs
`https://cdn.arcyai.com` in `script-src`.
## 3. Verify installation says no traffic yet [#no-traffic-yet]
`arcy.init()` never reached the selected environment. In order of likelihood:
1. The page that calls `arcy.init()` has not been opened in a browser since you deployed it.
Open it and reload while the check is watching.
2. The token in `init()` belongs to another environment. Copy it again from
[Installation](/settings/installation) with the right environment selected in the sidebar.
3. A network error is swallowing the call. Look for the request `init()` makes in the browser's
network tab.
## 4. Verify installation says the snippet carries another environment's token [#wrong-environment-token]
Traffic is arriving, but from a snippet copied off a different environment's Installation
page, for example the Development snippet in a Production deploy. Either switch the sidebar to
the environment that is receiving, or replace the token in the live snippet with the one
[Installation](/settings/installation) shows.
## 5. Verify installation says the origin is not verified [#origin-not-verified]
The token is right, but the request came from a domain this environment does not trust. The
verdict names the refused origin. If it is yours, add and verify it, then assign it to the
environment, on [Origins](/autopilot/origins). `localhost` never needs this.
## 6. Verify installation says identity verification is failing [#identity-verification-failed]
Sessions arrive, but the `userHash` you pass does not verify against the environment's Secret.
While Require identity verification is on, every affected session is served as anonymous, so
attributes and personalization stop for those users.
Check your signing code against the
[recipe](/quickstart#sign-user-ids-for-identity-verification): HMAC-SHA256 of the exact string
you pass to `identify()`, keyed with the Secret, hex encoded. The usual cause is a type
mismatch: ids that are integers on the server and strings in the browser. A signature over
`42` does not verify a call identifying `"42"`. If you replaced the Secret, redeploy the new
one; what replacing does is on [Environments](/autopilot/environments).
## 7. A custom attribute is not showing up [#attribute-not-showing]
Verify installation lists unknown attributes by name: a key that arrives without a declaration
is dropped, never stored. Declare it on [Attributes](/autopilot/attributes) and send it again.
Nothing is backfilled for traffic that arrived undeclared.
If the console shows this instead, the value's shape is the problem:
```
[arcy] identify() dropped "some_key": an attribute must be a string, number,
boolean, null, or an array of strings.
```
Flatten a nested object, a function or a `Date` to one of those shapes before passing it.
## 8. identify() or updateUser() seems to do nothing [#identify-does-nothing]
```
[arcy] identify() needs a user id. Ignoring the call.
[arcy] identify() was called before init(). Ignoring.
```
The first means the user id was empty, `undefined` or not a string. The second is a race
between your auth state and the script tag: call `identify()` where your session becomes
available, after `init()` has run once on the page.
`updateUser()` before any `identify()` or `identifyAnonymous()` sends nothing, because there is
no profile to update yet.
## 9. @types/arcy.js returns a 404 [#types-404]
```
npm error 404 Not Found - GET https://registry.npmjs.org/@types%2farcy.js
```
That package does not exist. arcy.js ships its own TypeScript types, so remove the line and
install only `arcy.js`. If your editor still reports missing types, run
`npm install arcy.js@latest`.
## 10. The chat panel stopped opening on a tab left open for a long time [#panel-stopped-opening]
ARCY ships the chat panel, the flow engine and the picker as separate files with a version
stamp in the name. A page open since before a release still holds the old names, so the first
click asks for a file that is gone. arcy.js then asks the CDN for the current names and loads
those; the visitor sees the panel open and nothing is logged.
Act only if the panel still does not open and you see:
```
[arcy] Failed to load https://cdn.arcyai.com/arcy.chat..js. The chat panel will not
open. If this page sets a Content-Security-Policy, it must allow scripts from
https://cdn.arcyai.com.
```
Then the retry failed too, and the cause is your policy ([section 2](#content-security-policy)),
an ad blocker or corporate proxy on the visitor's machine, or a filtering gateway on your
network. A reload always works. Do not build a reload prompt into your Product for this.
## See also
- [Quickstart](/quickstart)
- [Reference](/reference)
- [Installation](/settings/installation)
---
# Alerts
Source: https://docs.arcyai.com/autopilot/alerts
{/* screenshot: Autopilot > Alerts, three alert rows with Detect and Email me switches */}
**Autopilot > Alerts** holds three conditions ARCY watches for you. There is no custom alert
builder, and email is the only channel.
## Before you start
**Detect** can be changed by an organization admin only. **Email me** is yours: every teammate
sets it for themselves, whatever their role.
## Setting it up
Each row has two switches:
- **Detect** turns the condition on or off for the Product.
- **Email me** sends you an email when it fires.
| Alert | Fires when |
|---|---|
| **Flow broken** | 20% or more of attempts on one step fail in the last 60 minutes. |
| **Training failed** | A text or upload source finishes training with errors. |
| **Crawl failed** | A crawler source's run finishes with errors. |
## What it changes
Fired alerts appear under **Recent notifications** for the environment picked in the sidebar,
newest first, each with a title, a message and a time. An unread one carries **New**; **Mark
read** clears it. A **Flow broken** alert carries **Fix it**, which opens the failing step in
the flow builder.
Turning **Detect** off stops new notifications for that condition for everyone. Turning
**Email me** off stops your emails only; the notification still lands here.
## See also
- [Flows](/autopilot/flows)
- [Train](/autopilot/train)
---
# Attributes
Source: https://docs.arcyai.com/autopilot/attributes
{/* screenshot: Autopilot > Attributes, Custom group with one row marked Arriving but refused */}
**Autopilot > Attributes** is the list of attributes ARCY is allowed to store. A key your code
sends through `identify()` that is not defined here is ignored, so define first, then send.
## Before you start
Defining, editing and deleting attributes takes an organization admin. A member sees the list
and its status pills without the buttons.
Status pills read the environment picked in the sidebar. Sending the attribute from your
Product is described on [Quickstart](/quickstart).
## Setting it up
Press **New attribute** and fill in:
- **Display name**: what you see in the dashboard. Changeable later.
- **Code name**: the key your code sends. Permanent once created. Lowercase letters, numbers
and underscores only, starting with a letter, no trailing underscore, up to 64 characters.
A prefix of `user_`, `organization_` or `plan_` puts the attribute in that group.
- **Data type**: **Text**, **Number**, **Datetime**, **True/false**, **List**, **Object** or
**Object list**. A value of the wrong type is refused, never converted. Changeable later.
- **Description**: optional. For an Object, write what the document contains, since ARCY never
reads inside it.
Then send the key from your Product. Nothing shows on a user profile until your front end
sends it.
**Edit attribute** changes the display name, description and, for an attribute you defined,
the data type. **Delete attribute** archives it: stored values stay, and defining the same code
name again brings it back. Attributes marked **Set by ARCY** are computed by ARCY, refuse any
value sent through `identify()`, and cannot be deleted.
## What it changes
Every defined attribute can be used in text visitors read: a widget text, a flow's public
name or step question, a Persona field. Type `{{` in the field or press **Insert attribute**.
**Object** and **Object list** are the exception. ARCY stores the document as a whole, so
these two reach a [Persona](/autopilot/persona) field only, filter only by whether they are
set, and cannot split a report. To filter or greet on one field inside the document, send that
field as its own attribute. Each value is limited to 10 KB, 5 levels of nesting, 200 items in
an array and 50 keys in an object, and one profile holds at most 64 KB of attributes in total.
A value over a limit is refused and the rest of the payload is kept.
Each row carries a status pill for the selected environment:
| Pill | Meaning |
|---|---|
| **Never seen** | Nothing has arrived for this key. |
| **Arriving but refused** | Every value so far was refused. Hover for the reason. |
| **Arriving, nothing stored** | The key arrives, but the current value is empty. A call clears a value by sending `null`. |
| **Last seen** | Values are arriving and stored. |
The list stores no sample values, only whether something arrived and was accepted.
## When it goes wrong
**Every row reads Never seen.** Your Product is not sending attributes to this environment
yet. Check the token and the `identify()` call on [Installation](/settings/installation).
**A row reads Arriving but refused.** The reason is in the pill's tooltip: wrong data type,
over the size limit, a key that ARCY computes itself, a value that failed a built-in check, or
a key that arrived before it was defined. Fix the value in your code or change the data type
here.
**A refused key names the whole profile.** The profile has reached 64 KB of attributes. Nothing
stored was removed; send less, or send a summary instead of a document.
## See also
- [Users](/autopilot/users)
- [Organizations](/autopilot/organizations)
- [Quickstart](/quickstart)
---
# Customization
Source: https://docs.arcyai.com/autopilot/customization
{/* screenshot: Autopilot > Customization, theme gallery with one theme marked Default */}
**Autopilot > Customization** decides how the widget looks and what it says on its own,
before the agent answers anything. A Product holds several named themes, exactly one of
them **Default**, and every theme opens on a full-screen canvas where the widget is drawn at
real size beside the settings that change it.
## Before you start
- You need the admin role to create, edit or delete a theme. A member reads the gallery
and every sheet without a save bar.
- The theme canvas needs a screen at least 768 px wide. On a phone it shows a note and a
way back to the gallery.
- What the agent says in its answers is [Persona](/autopilot/persona), not this page.
## Themes and the theme canvas
{/* screenshot: Autopilot > Customization, theme canvas, Colors sheet open, Conversation state */}
**New theme** creates a theme from a name of up to 100 characters. Each card in the gallery
previews a live conversation. Its menu offers **Make default**, **Rename** and **Delete**.
Delete is unavailable on the default theme and on the last theme, so a Product always keeps
one.
Opening a card leaves the dashboard behind. Six sheets hold everything you can change, one
open at a time: **Colors**, **Texts**, **Sizes**, **Effects**, **Starter flows** and
**Settings**. The state switches render the widget as a visitor meets it: bar only, welcome
screen, conversation, recent chats, flows, settings, pinned, and a running flow. With two or
more locales enabled on [Localization](/autopilot/localization), a **Language** switch
previews the panel in another language. That preview changes nothing and is not saved.
Three facts the sheets do not say on screen:
- **Width** and **Max height** are percentages of the visitor's own screen, and the open bar
always takes the panel's width. **Resting bar width** is in pixels because there is no
panel to line up with.
- The welcome icon size also sizes the pinned button a visitor can shrink the widget to,
because that button is the same image.
- The web fonts are served from ARCY's own servers and load only when the chat opens.
Latin Extended is covered, so Turkish renders.
## Texts
The **Texts** sheet holds the three lines the widget says by itself, shared by every theme:
**Welcome headline** and **Welcome message**, 100 characters each, and **Input
placeholder**, 80 characters. Leave the message empty to show no greeting.
Each is written twice, on the **Identified** and **Anonymous** tabs. Neither copy falls
back to the other. One save writes both, and each tab shows how many unsaved edits it holds.
On **Identified**, type `{{` or press **Insert attribute** to reference an
[attribute](/autopilot/attributes). Write words around the tag: a visitor identified without
that attribute gets nothing where the tag was, and a placeholder that renders empty falls
back to ARCY's own hint. On **Anonymous** a reference typed by hand is refused on save.
Every other Liquid construct, page conditions included, works on both tabs.
These six texts are translatable on [Localization](/autopilot/localization). The rest of
the widget's own wording is ARCY's and arrives already translated.
## Starter flows
The **Starter flows** sheet lists up to 5 flows a visitor can start from the welcome screen
before typing a word. Tapping one runs it and spends no chat. **Identified** and
**Anonymous** each hold their own list, and one save writes both. Put anything that needs an
account on the Identified list only.
- **Add a flow** opens a picker of your existing flows. A flow needs a public name first,
because that name is the label a visitor reads.
- The picker never offers a flow this tab's [audience](/autopilot/flows) cannot reach. A
flow whose audience was narrowed after you featured it is marked in the list. Remove it.
- The lists are set once per Product. Publishing stays per environment, so a featured flow
not published in the environment you are looking at is marked as absent there.
## Settings
The **Settings** sheet holds the values a theme may not vary, shared by every theme.
Three uploads, each saved the moment the file is chosen: **Chat header logo**, **Welcome
screen icon** and **Chat bar icon**. PNG, JPEG, WebP or SVG. None falls back to another
and none is your Product's own icon. With nothing uploaded, the header shows your Product's
name and the other two show ARCY's default marks.
**Visitors can attach images**, off until you turn it on. A visitor then attaches up to
three PNG, JPEG or WebP images of up to 5 MB each to a message, from a button in the bar or
by dragging them onto the widget. The agent reads them and they appear with the
conversation on [Pulse](/pulse). Before you turn it on, set your privacy policy URL on
[Consent](/settings/consent). The switch warns while it is empty. How long images are kept
is on [Data retention](/privacy/data-retention), and how many a period allows is on
[Billing](/settings/billing).
**Visitors can move the chat bar**, off until you turn it on. The resting bar grows a handle
and a visitor can drag it anywhere. The position is remembered in that visitor's browser
only, the panel follows the bar, and phones are unaffected. Turning the switch off puts
every bar back.
## What it changes
- A theme is saved, not published. One save bar covers the theme and all six sheets, and
**Discard** puts all of them back. There is no draft and no per-environment state.
- A visitor's widget reads its theme once per page load. A save reaches them on their next
page, not in a tab they already have open. Refresh your own site to see a change.
- Under 640 px wide the widget ignores the width settings: the bar is full width and the
panel is a full-screen sheet.
- Recent chats in the panel are scoped to the visitor's browser, not to the id your Product
passes to `identify()`. A visitor who signs in on another device starts empty.
## When it goes wrong
- The **Identified** tab warns that identity checking is off: anyone can call
`arcy.identify()` with another person's id and read that copy with their attributes
filled in. Turn it on under [Identity verification](/autopilot/identity-verification)
before you write anything private.
- A starter flow row says it has no public name: give the flow one on
[Flows](/autopilot/flows), or visitors never see it.
- Leaving the canvas asks whether to discard: you have unsaved changes. Stay and save, or
leave and lose them.
## See also
- [Persona](/autopilot/persona)
- [Flows](/autopilot/flows)
- [Localization](/autopilot/localization)
---
# Environments
Source: https://docs.arcyai.com/autopilot/environments
{/* screenshot: Autopilot > Environments, Production marked Primary, row menu open on Replace secret */}
**Autopilot > Environments** lists the environments of your Product, each with its own Token
and Secret. Environments share content and keep user, company and event data apart.
## Before you start
- Every change here is admin only. Members see the list and can copy a Token.
- Every Product starts with **Production**, which is primary, and **Development**. Neither can
be renamed, and no environment you add can take either name.
## Setting it up
**Create.** Choose **New environment** and give it a name of up to 60 characters. The next
screen shows the Token and the Secret together. Copy the Secret now. It is stored in a form
nobody can read back, so it is never shown again.
**Copy the Token.** The **arcy.js Token** column has a copy control on every row. The Token
is what you paste into your snippet, and it is public: it appears in your page source.
**Replace a credential.** From the row menu, **Replace token** and **Replace secret** are
separate actions. Each takes effect the moment you confirm.
- A replaced Token stops every page still running the old one from starting ARCY until you
update the snippet.
- A replaced Secret stops identity verification from your server until you deploy the new
one. Pages are unaffected. The new Secret is shown once.
**Set the primary.** **Set as primary** appears on every row that is not primary yet. The
primary is where data lands when ARCY cannot tell which environment a request belongs to,
and its traffic is the only traffic checked against your verified
[Origins](/autopilot/origins). The previous primary keeps its Token and its data.
**Promote.** **Promote to...** publishes every flow and the Persona that this environment
publishes into an environment you pick. Choose the target, read the preview, then confirm.
**Element screenshots.** A switch per environment. On, picking an element for a flow step
stores a small cropped screenshot of it. Off, steps show text and an icon instead, and flows
build and run the same.
## What it changes
- Renaming changes only the label. The Token is untouched and every install keeps working.
- The primary environment cannot be deleted from here. Deleting the Product deletes it.
- Promote moves only what is published. The target keeps its Token, Secret, Origins and
settings. Anything the target publishes that the source does not is withdrawn, not deleted.
A row marked **Newer content** means the source serves an older copy than the draft, and
the target receives the draft. Promotion is refused when the source publishes nothing.
- Each promoted object is published on its own. If one fails, the row says why and the rest
go through. Running it again finishes the job.
- **Last seen** on a row is the last time a session arrived with that Token. **No data
received** means none has yet.
Deleting an environment cannot be undone. Its Token stops working and every session, event,
user and company recorded in it is deleted with it.
## When it goes wrong
**You lost a Secret.** It cannot be recovered. Use **Replace secret**, copy the new one, and
deploy it.
**A row says No data received although the snippet is live.** The page is running another
environment's Token. Compare the Token in your page source with the row, then verify the
install on [Installation](/settings/installation).
## See also
- [API key security](/security/api-key-security)
- [Origins](/autopilot/origins)
- [Identity verification](/autopilot/identity-verification)
---
# Flows
Source: https://docs.arcyai.com/autopilot/flows
{/* screenshot: Autopilot > Flows, Identified tab, one flow in Pending changes */}
A flow is a sequence of steps ARCY carries out inside your Product for a user, such as inviting a teammate. You build and publish flows on **Autopilot > Flows**. Steps are delivered through the chat, never as overlays on your page.
## Before you start
- The environment you are working in needs a verified domain assigned to it. Without one the element picker and the preview have no site to open. See [Origins](/autopilot/origins).
- arcy.js must have been seen on your Product at least once, or the builder cannot target elements. See [Quickstart](/quickstart).
- Your Plan sets how many flows you can hold. Past the cap, **Create flow** is disabled. See [Billing](/settings/billing).
## Setting it up
**Create flow** asks only for a **Name**. Only your team sees it. The new flow opens in the builder as a draft and reaches nobody until you publish it.
{/* screenshot: Autopilot > Flows, builder canvas with three steps and the step panel open */}
**Steps.** Each step does one thing. **Click** activates an element. **Fill** asks the user a question in chat, then types the answer into a field. **Navigate** opens a path such as `/settings/team` or a full `https://` address. A flow holds at most 30 steps.
**Picking the element.** **Target Element** opens the page you name in a new tab with the picker on. Click the element there and it lands in the step. Two controls tune how ARCY finds it later: **Matching**, which you loosen when ARCY finds nothing and tighten when it finds the wrong thing, and **If several match, use**, which picks the nth match from the top of the page. Turn on **This element's text is dynamic** for labels such as "3 items in cart". A page on a domain that is not verified for this environment is refused before any tab opens.
**Fill steps.** Write the **Question to ask in chat** as a full sentence, because the user reads it word for word. **Insert attribute** puts one of your [attributes](/autopilot/attributes) into the question or a URL, so `/orgs/{{ user.organization_id }}/settings` sends each user to their own page. Set **Expected input type (optional)** when the field itself does not say what it accepts. An answer that does not fit is refused and asked again.
**Triggers.** A step can carry triggers that watch a **Condition** while the step is active and then act: **Go to step** or **Dismiss flow**. Conditions read an attribute, the current page, an element's state, a text input's value, the time, whether the user is idle, or whether this is a first visit, combined with **AND** and **OR**. While a fill step waits for its answer, its triggers pause.
**Flow settings.** **Public name** is what users see when ARCY offers the flow. Leave it empty and the flow never reaches them. **Summary** is what the agent reads to decide when to offer the flow, so describe the task in the words a user would use. **Audience** is who the flow reaches. **Element wait limit** is a limit, not a delay: a step acts the moment its element appears and gives up after this many seconds, up to 60, default 30.
**Finish.** Turn on **End of the flow** on one step. If you mark none, the last step is the finish. The step still runs.
**Save, Preview, Publish.** Saving is one explicit action and every step has to be complete first. **Preview** runs the saved draft on your own site as you, in a new tab, and records nothing in analytics. **Publish** sends the saved copy to one environment at a time.
## What it changes
**Who reaches a flow.** A visitor is Identified when they have a user id and at least one attribute you sent us, and Anonymous otherwise. **Everyone** reaches every visitor. **Identified only** and **Anonymous only** reach one side. Persona, Customization and Localization apply the same split. A visitor the flow excludes never sees it: not in the widget's flow list, not among the starter flows, not in an agent suggestion. The **Identified** and **Anonymous** tabs above the list show what each side can reach.
**Publishing.** Each environment serves its own copy and is in one of four states: **Never published**, **Published**, **Pending changes** when the environment serves an older copy than your saved draft, and **Unpublished**. Publishing overwrites the copy an environment serves and there is no version history and no way back to the old one. Saving a live flow moves that environment to **Pending changes** until you publish again. **Unpublish** takes the flow out of one environment at once and leaves the flow itself untouched.
**Measurement.** ARCY counts how far users get through every flow, including users who did the steps on their own without opening the widget. A click step and a fill step are measured, and a step still counts when the element's text or position has changed since you picked it. A navigate step is measured when it opens a page on your own Product and the URL has no wildcard. A funnel needs two measurable steps, and the settings panel says why a flow has none. The numbers appear on [Lift](/lift), reached from **View on Lift** in the builder.
**Deleting.** **Delete** removes the flow, its steps and its funnel. A flow that is live in any environment must be unpublished everywhere first.
## When it goes wrong
- **A step cannot find its element.** The flow stops after the wait window, the user sees a short apology in their language and can keep chatting. The stop is recorded as an error on [Pulse](/pulse), and if ARCY finds a replacement it offers the fix in the step.
- **The list says flows are serving an older copy.** Those environments hold pending changes. Open each flow and publish again.
- **Your save is refused.** Someone on your team saved the same flow while you had it open. Copy what you need, then choose **Reload the flow**.
- **The picker opens your site but nothing arrives.** Switch to the new tab: ARCY writes the reason there. The usual causes are arcy.js missing on that page, a Content-Security-Policy that blocks `cdn.arcyai.com`, or the page carrying a different environment Token.
- **Publish is disabled.** Save first, and give the flow at least one step.
## See also
- [Pulse](/pulse)
- [Lift](/lift)
- [Customization](/autopilot/customization)
---
# Identity verification
Source: https://docs.arcyai.com/autopilot/identity-verification
{/* screenshot: Autopilot > Identity verification, Require identity verification off, Identity checks chart showing all four outcomes */}
**Autopilot > Identity verification** shows whether the user ids your pages claim through
`identify()` arrive with a valid signature, and lets an admin make that signature required.
It reads the environment selected in the sidebar.
## Before you start
- Signing happens on your server with the environment's Secret. The recipe is in the
[Quickstart](/quickstart#enforce-identity-verification).
- Only a Workspace Admin can change **Require identity verification**. Everyone can read
the chart.
## Setting it up
1. Add the signature to your `identify()` calls, following **Sign the users you identify**
on the page. **Hand it to a coding agent** copies the whole task, written for the agent
you pick: where the Secret is read, how the hash is made, how it reaches `identify()`.
2. Deploy, then watch **Identity checks**. Each bar is one hour of sessions that tried to
identify, split by outcome.
3. When the bars are **Verified** and **Unverified** has gone to zero, turn on **Require
identity verification**.
## What it changes
Off, ARCY checks every signature, records the outcome in the chart, and turns nobody away.
On, a session whose claim does not verify is served as anonymous. The whole `identify()`
call is dropped: the user id and every attribute sent with it, including name, email and
plan. No profile is created or updated. The call still succeeds from the browser's point of
view, so the widget can greet the user by the name it was handed while ARCY stores nothing.
The chart splits sessions into **Verified**, **Verified (previous secret)**, **Unverified**
and **Refused**. What each outcome means for one session is explained on
[Users](/autopilot/users), where the same outcome is shown per session.
## When it goes wrong
**Unverified rises after you turned the check on.** Users are arriving as anonymous. Open the
browser console on an affected page: the widget warns on every call that is missing
`userHash`. Fix the signature before anything else.
**Refused rises after you replaced the Secret.** A server is still signing with the old
Secret. Deploy the new one. Replacing happens on [Environments](/autopilot/environments),
not here.
**Everything is Unverified although your code signs.** Sign the exact string you pass to
`identify()`. `String(user.id)` and `user.id` are different inputs.
## See also
- [Quickstart](/quickstart#enforce-identity-verification)
- [Environments](/autopilot/environments)
- [Users](/autopilot/users)
---
# Localization
Source: https://docs.arcyai.com/autopilot/localization
{/* screenshot: Autopilot > Localization, Translation editor filtered to Not completed */}
**Autopilot > Localization** is where you enable a locale, translate every text a visitor
reads, and set the agent's reply language. It applies to every environment of the Product.
## Before you start
Adding or deleting a locale, changing the agent language and typing translations take an
organization admin. A member can read every card.
BETA supports two locales: English (US) and Turkish (Türkiye). English (US) is on for every
Product and is the language you write your content in. Ask us for any other language.
## Setting it up
1. Press **New locale**, pick the locale and press **Create locale**. The Product now accepts
translations for it.
2. Tell ARCY which locale each visitor is in. Send `locale_code` as an attribute in
`identify()`, or pass `contentLocale` to `arcy.init()` when you know the region before the
visitor signs in. The most recent one wins. See [Reference](/reference).
3. Under **Agent language**, set **Language**, the language the agent replies in by default,
and **Reply language policy**: **Match the user** replies in the visitor's language when it
is clear, **Always use the set language** replies in the chosen language whatever the
visitor writes.
4. In the **Translation editor**, pick the language and type a translation beside each English
string. Edited rows are marked **Unsaved**. Save the page. Each string saves on its own, so
one refusal never blocks the rest; a refused string keeps your text and its reason under
the field.
Clear a field and save to remove a translation. You cannot switch language while you have
unsaved changes.
## What it changes
A visitor reads your content in their locale where a translation exists and in English where
it does not. Without `locale_code` or `contentLocale`, ARCY uses the browser language, then the
agent language. With two locales enabled, the chat panel's Settings sheet offers a language
choice, and that choice outranks everything your Product sends. See
[Customization](/autopilot/customization).
**Translation progress** shows, per language, how many strings are **Translated**, how many
are **Missing** and how many are **Out of date**, which means the English changed after the
translation was written. An out-of-date translation is still served. Press **Still correct** on
its row to clear the flag without retyping it.
The editor's **Not completed** view shows what is left. Rows are grouped by area, and texts the
widget shows to identified and anonymous visitors separately appear twice, so translate both.
See [Flows](/autopilot/flows) for who counts as which. A row whose English uses a variable the
translation does not says so and still saves.
**A flow cannot be published while an enabled language is missing its public name or
summary.** The refusal names the language and the field. Flows published before you added the
language keep running untranslated until you translate them.
**Delete locale** stops serving every translation for that locale, and its visitors fall back
to the agent language. This cannot be undone. English (US) has no delete action.
## When it goes wrong
**A visitor reads English on a translated page.** Their locale never reached ARCY. Check that
`identify()` sends `locale_code` with the exact code shown in the **Code** column, `tr-TR` and
not `tr`, or that the visitor has not picked English themselves in the chat panel.
**Publishing a flow is refused for a missing translation.** Open the editor, filter to **Not
completed**, fill the flow's public name and summary for the named language, save, and publish
again.
## See also
- [Customization](/autopilot/customization)
- [Flows](/autopilot/flows)
- [Reference](/reference)
---
# Organizations
Source: https://docs.arcyai.com/autopilot/organizations
{/* screenshot: Autopilot > Organizations, list with one named account and one showing only its id */}
**Autopilot > Organizations** groups the end users of the selected environment by their
`organization_id` attribute. There is no organization object to create: an account appears
once one of its members identifies with that attribute set.
## Setting it up
Send the id, and a name so the list shows more than the id:
```js
arcy.identify("user_123", {
organization_id: "org_acme",
organization_name: "Acme Inc",
})
```
Every attribute prefixed `organization_` or `plan_` rolls up to the account, taking the value
from the most recently seen member that sent it. Declare them first on
[Attributes](/autopilot/attributes).
## What it changes
**The list.** One row per account: **Organization** (the name with the id under it, or the
id alone), **Members**, **Last seen** across all members, **Origin(s)** and **Members
accepted**, the members whose latest consent answer is a grant over all members. Search
matches id and name. Sort by organization, members or last seen. Search, sort and paging run on the
server. Organization Segments sit under the table; see [Segments](/autopilot/segments).
**The account page.** Click a row. The header shows **Organization ID**, **Members** and
**Sessions**. **Attributes** is the account-level bag rolled up from members. **Members**
lists every user carrying the id, with **Email**, **User ID** and **Consent**, each linking to
the person's page on [Users](/autopilot/users); search it by name, email or id, and sort by
**Consent** to find who has not accepted. What an answer means is on
[Consent](/settings/consent). **Sessions** is
one table across every member, one row per session, with the same columns as a user's own
session table plus **User**. Sort by **Struggle** and open the top row with **See activity**
to reach the hardest session in the account. The columns, the identity outcomes and the
Activity page are described on [Users](/autopilot/users).
There is no merged timeline for an account and no export. The unit at account level is the
session.
## When it goes wrong
**An account is missing.** No member has identified with `organization_id` in this
environment yet, or the attribute is not declared. Check [Attributes](/autopilot/attributes)
and the environment selected in the sidebar.
**An account shows only its id.** No member has sent `organization_name`. The page says so
under the header.
**Two accounts for one customer.** Members are sending two different `organization_id`
values. Send one.
## See also
- [Users](/autopilot/users)
- [Segments](/autopilot/segments)
- [Attributes](/autopilot/attributes)
---
# Origins
Source: https://docs.arcyai.com/autopilot/origins
{/* screenshot: Autopilot > Origins, one origin Verified and assigned, one Pending with its DNS TXT record open */}
**Autopilot > Origins** is where you add the domains your Product runs on and prove you
control them. ARCY refuses sessions from a domain until it is verified here and assigned to
an environment.
## Before you start
- Only an admin can add, verify, edit, assign or remove an origin. Members see the list.
- Your Plan sets how many origins you can hold, pending and verified together. See
[Billing](/settings/billing). At the cap, **Add origin** is disabled until you remove one.
- You need access to the DNS records of the domain.
## Setting it up
1. Choose **Add origin** and enter the full address with its scheme, for example
`https://myapp.com`.
2. The new row shows **Pending** and the DNS TXT record to publish: type `TXT`, a name of
`_arcy-verify.` followed by the hostname, and a generated value. Add it with your DNS provider.
3. Once the record has spread, choose **Verify**. The row changes to **Verified**.
4. Open the environments menu on the row and tick every environment that may serve sessions
from this origin. Each change saves as you make it.
Which hostnames one proof covers, where the check runs, and how `localhost` is treated are on
[Session security](/security/session-security).
## What it changes
- A **Pending** origin is trusted for nothing. A page on it cannot start ARCY.
- A **Verified** origin assigned to no environment is refused too, and the row says so.
Assign at least one environment.
- Editing the address keeps the environments you assigned. If the domain itself changes, the
row goes back to **Pending** and you publish a new record for the new domain.
- Removing a pending origin happens at once. Removing a verified one asks you to type the
domain first.
Removing a verified origin cannot be undone. Every page on that domain stops starting ARCY
until you add and verify it again.
## When it goes wrong
**Verify fails.** The name or the value does not match, or the record has not spread yet.
Compare both against the row character by character, wait for your DNS provider's
propagation time, then choose **Verify** again.
**Sessions are refused after verifying.** Open the environments menu on the row. A verified
origin serves only the environments ticked there, and the environment whose Token your
snippet carries must be one of them.
## See also
- [Session security](/security/session-security)
- [Environments](/autopilot/environments)
- [Installation](/settings/installation)
---
# Persona
Source: https://docs.arcyai.com/autopilot/persona
{/* screenshot: Autopilot > Persona, Identified tab, Choose tone dialog open */}
**Autopilot > Persona** holds what the agent is told before every conversation: its
instructions, the facts it always knows, and the message it sends when it cannot answer.
Each environment has its own Persona, and a save is live there at once.
## Before you start
- You need the admin role to save. A member reads the page and gets no save bar.
- The sidebar's environment switcher picks which Persona you edit. Switching with unsaved
edits drops them, and the page tells you so.
## Setting it up
Every field is written twice, on the **Identified** and **Anonymous** tabs. Neither copy
falls back to the other, and one save writes both. Who counts as identified is defined on
[Flows](/autopilot/flows).
- **Custom instructions**, 5,000 characters: tone, focus and what comes first. It cannot
change how replies are formatted. **Choose tone** appends one of five ready voices under
what you already wrote. Press **Apply**, then edit the words as ordinary text.
- **Always-on knowledge**, 5,000 characters: facts the agent knows on every page, for
every user. **Add structure** appends twelve headings and no example facts. Write under
each heading and delete the ones you have nothing to say under. Anything longer than a
few sentences belongs in [Train](/autopilot/train).
- **Fallback message**, 1,000 characters, with bold, italic, links and lists: what a
visitor reads when the agent cannot answer from your material. Both copies are required.
The save stays disabled while either is blank, and the page names the blank tab.
On **Identified**, type `{{` or press **Insert attribute** to reference an
[attribute](/autopilot/attributes). On **Anonymous** a reference typed by hand is refused
on save, because there is nobody to fill it in from. The two prompt fields are the only
place an Object or Object list attribute may be referenced. Its value enters the prompt cut
at 2 KB, and the page warns once: that value is written by your own end users and is sent
on every turn for that user.
## What it changes
- Saving makes the Persona live in the selected environment. There is no publish step. To
copy one environment's Persona over another's, use **Promote to...** on
[Environments](/autopilot/environments).
- A turn the agent cannot answer sends the fallback message and is recorded as a content
gap on [Pulse](/pulse). A greeting is never a gap.
- A Product with nothing trained answers most questions with the fallback message until you
add a source.
## When it goes wrong
- The save is refused with a conflict error: someone saved this Persona while you had it
open. Reload, then redo your edits.
- The **Identified** tab warns that identity checking is off: anyone can call
`arcy.identify()` with another person's id and read that copy with their attributes
filled in. Turn it on under [Identity verification](/autopilot/identity-verification)
before you write anything private.
- **Choose tone** or **Add structure** refuses: the result would pass 5,000 characters.
Shorten the field first.
## See also
- [Train](/autopilot/train)
- [Customization](/autopilot/customization)
- [Environments](/autopilot/environments)
---
# Segments
Source: https://docs.arcyai.com/autopilot/segments
{/* screenshot: Autopilot > Users, Segments section under the table with three cards and the next refresh countdown */}
A Segment is a group of users, or of accounts, that ARCY found in an environment on its own.
The section sits under the table on **Autopilot > Users** and on Organizations, and each
card opens its own page.
## Before you start
- Segments are built from live sessions only. Your own testing never creates one and never
counts toward one.
- ARCY starts looking once an environment has enough tracked people over the last 30 days.
Until then the section says how many it has and how many it needs.
- Segments belong to one environment. Switch in the sidebar to see another's.
## What it changes
**The card.** A plain sentence naming the behaviour, the member count, the change since last
week, and the date of the count. A pattern that stops standing out is marked **Quiet** with
a date, and stays where it is. The section header says when the next refresh is due.
**Two clocks.** Once a week ARCY looks for new Segments; only that creates one. Every night
it recounts every Segment; that never renames anything. A Segment's sentence and rule are
written when it is found and never rewritten, so a link you pasted last month still matches
the page.
**The Segment page.**
- **Why these people are in it**: the rule, as a short list of lines. Everybody in the group
matches every line, and nothing else puts anybody in.
- **When ARCY found it**: how many matched and how many did not at the time, and how far
above chance that was.
- **Three sessions that show it**: the same three for everybody, so a colleague opening your
link sees what you saw. **Open session** leads to the Activity page.
- **Who is in it**: every member, with the date they entered.
- **Write it up**: **Copy problem statement** puts the sentence, the element and page, the
count and the evidence links in one block for a ticket.
- **One thing worth trying**: a suggestion, not a reading of the data.
Every number on a Segment comes from a query; the model writes only the sentence. A rise or
a fall is a change in the count, and ARCY does not say what changed it.
Organization Segments group accounts by how use is spread across their people: nearly
all the use in one person, most of the account never seen, nobody new, every new arrival
hitting the same wall, plenty of looking and nothing submitted.
A Segment never contacts your end users. Nothing about it opens the widget or starts a
conversation.
## When it goes wrong
**Nothing to show yet.** Either the environment is below the population ARCY needs, and the
section shows the gap, or ARCY looked and found no group large or distinct enough. It looks
again every week.
**This Segment is not in the environment you are looking at.** The link belongs to another
environment. Switch in the sidebar.
## See also
- [Users](/autopilot/users)
- [Organizations](/autopilot/organizations)
- [Attributes](/autopilot/attributes)
---
# Train
Source: https://docs.arcyai.com/autopilot/train
{/* screenshot: Autopilot > Train, sources table with one Web crawler in Training and one Walkthrough Trained */}
A source is one body of material the agent answers from. You add and train sources on **Autopilot > Train**.
## Before you start
- A **Web crawler** or a **Walkthrough** only runs on a domain verified for this environment. See [Origins](/autopilot/origins).
- Your Plan sets how many sources you can hold. Past the cap, adding one is refused until you delete one or change Plan. See [Billing](/settings/billing).
## Setting it up
**Add source** offers five types:
- **Web crawler.** Give it a **Starting URL**. It finds the other pages from your sitemap and from links at or below that path. Turn off **Allow linking to this source in answers** for pages that should stay unlinked.
- **Flows.** Pick **Flows to suggest**, so the agent can describe and offer them. See [Flows](/autopilot/flows).
- **Text.** Up to 15,000 characters. Markdown works.
- **File upload.** PDF, DOC, DOCX, TXT or MD, 10 MB at most. A file cannot be replaced: delete the source and upload again.
- **Walkthrough.** Choose a **Starting page**, then **Start walkthrough**. Your Product opens in a new tab and every screen you visit becomes one document of its interface text: headings, menus, buttons, field labels. Nothing you type, no dropdown options, no table rows and no screenshots are taken. One per Product.
Then press **Train** on the row. The row reads **Training** with a page count, then **Trained**. Runs are listed under **Training log**, saved pages under **Documents** with their extracted text.
Training is incremental: a second **Train** reads only pages it has not seen. To reread pages you changed, use **Fetch this document again** on one page, or **Retrain from the start** on the source, which deletes every saved page and crawls again. **Leave out of future crawls** drops one page for good. **Stop training** ends a crawl after its current page and keeps what it saved.
When your Product changes, **Walk again** replaces every screen the moment you stop. **Leave this screen out of training** survives a re-walk, so an internal page never becomes an answer.
## What it changes
- One crawl saves up to 1,000 pages. A larger site continues from page 1,001 on the next **Train**.
- A page over 5 MB is skipped and named in the log.
- The crawler identifies itself as `ARCYBot/1.0` and obeys `robots.txt`, including `Crawl-delay`. On a site that blocks all crawlers, add a group for it:
```
User-agent: ARCYBot
Allow: /
```
- From a crawled page ARCY keeps the content and drops the header, navigation, sidebar and footer.
- Crawled pages cannot be edited. To correct one, leave it out and add the corrected text as a **Text** source.
- A Walkthrough writes a short summary per screen on every **Train**, and the walk stops on its own after 30 minutes.
- Deleting a source removes its saved content at once.
## When it goes wrong
- **Nothing is fetched and the message names the domain.** The domain is not verified for this environment. Verify it on [Origins](/autopilot/origins), then press **Train** again. Pages already saved stay in place.
- **The log says pages were skipped because of robots.txt.** Your site disallowed `ARCYBot`. Add the group above. This is not counted as a failure.
- **Far fewer pages than your site has.** The pages are not linked and there is no sitemap. Publish a sitemap.
- **The walkthrough tab opens without the ARCY bar.** The link expired, the page carries another environment's Token, or arcy.js is not installed there. The reason is written on the page.
## See also
- [Persona](/autopilot/persona)
- [Pulse](/pulse)
- [Reference](/reference)
---
# Users
Source: https://docs.arcyai.com/autopilot/users
{/* screenshot: Autopilot > Users, list filtered to Identified, one row's actions menu open */}
**Autopilot > Users** lists every end user arcy.js has seen in the environment selected in
the sidebar, identified or anonymous, and opens each one's attributes and sessions. Use it to
confirm `identify()` is reaching ARCY and to look one person up.
## Before you start
A user appears in the environment they were seen in. An empty Production list beside a busy
Development list means nobody has identified through your live Token yet. Sessions from
`localhost` are listed with their origin shown.
## Setting it up
Nothing to configure. What a row can show depends on what your `identify()` call sends:
```js
arcy.identify("user_123", {
user_first_name: "Ada",
user_last_name: "Lovelace",
user_email: "ada@example.com",
})
```
Send none of these and the row shows only the user id. Every attribute must be declared
first on [Attributes](/autopilot/attributes).
## What it changes
**The list.** One row per user: **User** (the name, or the id, with **Anonymous** for a
visitor who never identified), **Last seen**, **Sessions**, **Origin(s)** and **Consent**, the
person's latest answer. Search matches id, name and email. Filter by **All users**,
**Identified** or **Anonymous**. Sort by user, last seen or sessions. Search, sort and paging
cover every user. The Segments ARCY found in this environment
sit under the table; see [Segments](/autopilot/segments). The **Consent** section under them
is explained on [Consent](/settings/consent).
**The user page.** Click a row. The header carries **User ID**, **First seen**, **Last
seen**, **Sessions**, **Events** and **Time in product**, and links to the user's
organization when one arrived. **Attributes** lists everything `identify()` sent, labelled
with the display name from your registry; hover a label for the code name. **Sessions**
lists every session in the date range you pick, with **Origin**, **Entry page** (identifiers
scrubbed, so `/orders/12345` reads `/orders/:id`), **Started**, **Length**, **Events**,
**Struggle** and **Identity**. **Consent history** under the sessions lists every answer this
person gave, each linked to its session.
**Identity** names one of five outcomes, and hovering explains it. **Verified**: signed
with the current Secret. **Verified (old key)**: signed with a Secret you have replaced.
**Unverified**: a user was claimed with no signature, so the claim could not be checked.
**Refused**: the signature did not match, so the session was treated as anonymous.
**Anonymous**: `identify()` was never called.
{/* screenshot: Autopilot > Users, one session's Activity page with a struggle mark on a clicked element */}
**Activity.** **See activity** on a session row opens that session on its own page, with an
address you can share. Every event the person produced is listed in the order
it happened, grouped by page, with the time since the session started and the wall clock
time. ARCY's own moments, the widget opening, a question, a flow started and how it ended,
are in the same list. Three struggle marks
appear on the event that caused them: **Repeated clicks**, **Came back to this page** and
**Longer here than usual**. They are worked out from what the person did in your Product, never
from ARCY's own events. A very long session is cut off at the end, and
the page says so.
**Consent** in the Activity header reads **Accepted on your banner**, **Accepted in the chat**,
**Refused on your banner**, **Refused in the chat**, or **Not answered**. The model is on
[Consent](/settings/consent).
## When it goes wrong
**Nobody appears although identify() runs.** Check the environment in the sidebar, then the
Token in your page source against [Environments](/autopilot/environments).
**A user is Anonymous although your code sends the right id.** The claim did not verify and
the check is required. See [Identity verification](/autopilot/identity-verification).
**An Activity page is empty.** Nothing is recorded until the visitor agrees, on your banner
or in the chat. The page says the session reported no answer: the person never answered, or
your banner does not call `arcy.consent()` yet. See [Consent](/settings/consent).
## See also
- [Organizations](/autopilot/organizations)
- [Segments](/autopilot/segments)
- [Attributes](/autopilot/attributes)
---
# Certification status
Source: https://docs.arcyai.com/compliance/certification-status
ARCY AI is offered as a BETA product. The table below is our compliance status as it stands today, not where we expect to land. For the binding legal terms, see [arcyai.com/terms](https://arcyai.com/terms), [arcyai.com/privacy](https://arcyai.com/privacy) and, for Turkish data subjects, [arcyai.com/kvkk](https://arcyai.com/kvkk).
| Standard | Status |
| --- | --- |
| GDPR | In progress. A DPA is available on request; see [Data processing agreements](/compliance/data-processing-agreements). |
| CCPA | Planned after launch. |
| SOC 2 Type II | In progress. |
| External penetration test | Scheduled for September 2026. |
| Uptime SLA | Not yet formalized. Live status at [status.arcyai.com](https://status.arcyai.com). |
Do not claim a certification on ARCY's behalf that is not listed here as complete. Hosting, encryption and access controls are on [Infrastructure](/security/infrastructure).
---
# Data Processing Agreements
Source: https://docs.arcyai.com/compliance/data-processing-agreements
Email **contact@arcyai.com** to request any of the following. We respond within 24 hours.
- Our Data Processing Agreement, ready to sign.
- Our completed security questionnaire, or answers to yours.
- The AWS region your data is processed in, when your own DPA or a customer contract needs it named.
- A written answer on whether we can meet a data-residency requirement. Enterprise workspaces are evaluated case by case.
If you are in a regulated industry, HealthTech, FinTech or government, write before you sign up. We will tell you directly whether we can meet your requirements at this stage.
Our current certification and audit status is on [Certification status](/compliance/certification-status), and the third parties a DPA has to name are on [Sub-processors](/compliance/sub-processors).
---
# Sub-processors
Source: https://docs.arcyai.com/compliance/sub-processors
| Provider | Purpose |
| --- | --- |
| Amazon Web Services (AWS) | Hosting, storage, database, and AI inference through Amazon Bedrock |
| Clerk | Authentication, account management, and billing through Clerk Billing |
| Stripe | Payment processing behind Clerk Billing |
| Resend | Transactional email |
| Google | Calendar scheduling when someone books a call with us |
None of these providers sells or shares your data. See [How AI request content is handled](/security/ai-request-content) and [Infrastructure](/security/infrastructure) for the underlying detail, and [arcyai.com/privacy](https://arcyai.com/privacy) for the legal document this table mirrors. Link to this page from your own DPA rather than copying the table, so your list stays current; the wording is on [Sub-processor / DPA disclosure](/legal-templates/sub-processor-dpa).
---
# Create account
Source: https://docs.arcyai.com/getting-started/create-account
Signing up takes you from nothing to the Installation page of your first Product in one
sitting. If a colleague already uses ARCY, do not sign up: ask them to invite you from
**Settings > Team** and you join the workspace your team already has, with any email address.
## Before you start
- An email address on your company's own domain. Gmail, Outlook, Yahoo and disposable
addresses do not open a workspace. See [the work email rule](#the-work-email-rule).
- A card. Every plan starts with a 14-day free trial entered through checkout. What each plan
includes is on [Billing](/settings/billing).
## Signing up
### Sign up
Open [the sign-up page](https://app.arcyai.com/sign-up). Sign up with your work email
and a password, or continue with Google using an account on your company domain. The method
you pick is the method you [sign in](/getting-started/sign-in) with later. An email sign-up
sends you a code to type back; Google skips that step.
### Name your workspace
{/* screenshot: workspace/new, the You have no workspace yet form */}
A workspace is your company inside ARCY: its Products, environments, teammates and billing.
Name it after your company. You can rename it later from **Settings > Account**.
### Choose a plan
Pick a plan and complete checkout. Plans differ in capacity, never in features. Until a
workspace has a plan, you cannot create a Product.
### Name your Product
{/* screenshot: onboarding, the Name your product card */}
A Product is one piece of software you install ARCY in. You can rename it later. Every
Product is created with two environments:
- **Production**, for your live site. It answers only for a domain you have verified.
- **Development**, for building and testing. It accepts any address.
### Save both secret keys
{/* screenshot: Settings > Installation, the keys dialog open on a new Product */}
Each environment's secret key is shown once, in this dialog, and nowhere else. ARCY keeps
only an encrypted copy. Copy both, or use **Download as an environment file**, before you
tick **I have saved both secret keys somewhere I can find them again.** A lost key can only
be replaced, never recovered. See [Environments](/autopilot/environments).
### Install
The dialog closes onto **Settings > Installation**, with your snippets already carrying the
right token. Follow the [Quickstart](/quickstart) from there.
## The work email rule
ARCY opens a workspace only for an address on your company's own domain. The check runs
after the workspace is created, not on the sign-up form. A personal address opens the
workspace and loses it a moment later, and you land on a screen titled **Your workspace was
not created**. Two ways forward:
1. **Sign out** and start again with your work address.
2. Ask a colleague to invite you. An invited member can use any address.
If your domain is legitimate and you were blocked anyway, use **Talk to us.** on that screen.
The rule keeps applying to the person who created the workspace: their active email has to
stay on a company domain. Invited members are never subject to it.
## See also
- [Sign in](/getting-started/sign-in)
- [Quickstart](/quickstart)
- [Team](/settings/team)
---
# Sign in
Source: https://docs.arcyai.com/getting-started/sign-in
Sign in at [the dashboard](https://app.arcyai.com/sign-in); you land on Pulse.
Use the method you signed up with: your work email and password, or Google. Which address
counts as a work email is on [Create account](/getting-started/create-account#the-work-email-rule).
## Forgot your password
Use the forgot-password link on the sign-in form. ARCY emails a code to your work address;
enter it and set a new password.
If you signed up with Google you have no password to reset. Continue with Google, or set a
password from **Settings > Account** under **Password** if you want both ways in.
Setting or changing a password signs out every other session on every device. You stay
signed in where you made the change.
## You have no workspace yet
A sign-in that belongs to no workspace lands on a screen titled **You have no workspace yet**.
Two cases:
- **You expected an invitation.** Do not create a workspace. Ask an admin on your team to check
**Settings > Team**: a pending invitation shows as **Invited** there and can be cancelled and
resent.
- **You were removed from a workspace.** Sign-in still works, but there is nothing behind it.
An admin has to invite you again.
Creating a workspace here is the same step as at sign-up, so
[the work email rule](/getting-started/create-account#the-work-email-rule) applies.
## Switching workspaces
If you belong to more than one workspace, switch with the workspace picker in the sidebar.
Switching returns you to Pulse.
## Signing out
Open your name at the foot of the sidebar and choose **Sign out**. The two screens above carry
their own **Sign out** button.
## Signed in, but the widget stopped answering
That is a billing state, not an access one. See [Billing](/settings/billing).
## See also
- [Create account](/getting-started/create-account)
- [Account](/settings/account)
- [Team](/settings/team)
---
# AI processing disclosure
Source: https://docs.arcyai.com/legal-templates/ai-processing
ARCY AI uses a third-party AI model to answer questions and to run the flows you author inside your Product. If you are subject to automated-decision-making disclosure requirements, GDPR Article 22 and its equivalents, your privacy policy needs a disclosure for this, separate from your general data-collection paragraph.
This is boilerplate, not legal advice. Whether this counts as automated decision-making with legal or similarly significant effect under GDPR Article 22 depends on which flows you published and what they do. Have your own counsel assess it for your configuration.
## What to paste
```text
Automated Processing and AI Features
[Your Product Name] uses an AI assistant, powered by ARCY AI, that may:
- Answer your questions using context about your account and how you use
[Your Product Name]
- Carry out a pre-authored sequence of steps inside [Your Product Name] on
your behalf, such as navigating to a page, clicking a button, or filling in
a form, when you ask for help with a task we have built a guided flow for
Every step the assistant runs was authored by our own team in advance and
points at a specific element of [Your Product Name]. The assistant does not
decide on its own what actions to take and does not invent a path through
the product it has not been given.
This feature is powered by a third-party AI model. Neither [Your Company
Name] nor ARCY AI uses your conversation content, session data, or
behavioral data to train AI models, ours or the model provider's. This
feature is not used to make legal or similarly significant decisions about
you (for example, decisions about eligibility, pricing, or account status)
without human review.
You can decline this feature at any time by [describe your opt-out
mechanism, e.g. "closing the assistant panel" or "disabling it in account
settings"].
```
## Notes on filling this in
- The sentence about legal or similarly significant decisions is accurate only if it is true of the flows you published. If a flow can take an action with real consequence, submitting a payment or deleting data, get specific legal advice on Article 22 rather than relying on this paragraph.
- Describe only the flows you published for your users, not every capability ARCY offers. What a user can trigger is exactly what you published for that environment; see [Flows](/autopilot/flows).
- Before referencing model retention in your own disclosure, read [How AI request content is handled](/security/ai-request-content): the model provider retains no request content, ARCY's call log records cost rather than content, and the conversation itself is stored unless you switch that off.
---
# Cookie policy disclosure
Source: https://docs.arcyai.com/legal-templates/cookie-and-storage
arcy.js sets two first-party cookies on your own domain and stores a handful of keys in `localStorage` and `sessionStorage`. None of it serves advertising, none of it follows anyone across sites, and nothing except the consent record is written before the visitor has agreed. How that agreement is asked for, and how your banner and the chat share one answer, is on [Consent](/settings/consent).
Paste the block below into your own cookie policy, then enter that page's URL as the **Cookie policy URL** on the Consent card of the [Product](/settings/product) settings page. Until you do, the ask in the chat links [our own cookie policy](https://www.arcyai.com/cookie-policy), which describes the same storage but is our page rather than yours.
This is boilerplate, not legal advice. Have your own counsel review it before publishing.
## What to paste
```text
ARCY AI (in-product assistance)
ARCY AI, which powers in-product guidance inside [Your Product Name], sets
two cookies on [yourdomain.com] and stores a small amount of data in your
browser. Apart from the record of your answer, none of it is written until
you have agreed to it.
| Name | Purpose | Lifespan |
|------------------------|-------------------------------------------------------------------------|------------|
| arcy.anon. | A random identifier for this browser, so the assistant recognises you | 400 days |
| | on a return visit and your past conversations come back | |
| arcy.consent. | Your answer to the question above, when you gave it, and whether you | 400 days, |
| | gave it on this site's cookie banner or inside the assistant | 6 months |
| | | if you |
| | | declined |
It also stores the following in your browser's local storage, which is not
sent to any server:
| Category | Purpose | Lifespan |
|---------------------|-----------------------------------------------------------------------|-----------------------------------|
| Assistant state | Where you moved the assistant, whether you shrank it, and the | Until you clear browser storage |
| | language you chose for it | |
| Appearance | The assistant's colours, so it does not flash unstyled on a reload | Until you clear browser storage |
| Conversation | The current conversation, so it continues if you move between pages | 24 hours after your last message |
| Session | The current session with the assistant | Until you clear browser storage |
| Guided flow | A guided walkthrough in progress, so it survives a page change | Until you clear browser storage |
And the following for the current browser tab only, gone when you close it:
whether this tab is a first visit or a return, a draft walkthrough being
previewed, and a marker that stops the assistant retrying a request that has
already been refused.
None of this is used for cross-site advertising or third-party tracking. It
is used only to operate the in-product assistant within [Your Product Name].
You can withdraw your agreement at any time from this site's cookie settings,
which deletes everything listed above from your browser.
```
## Technical reference for your CMP or cookie scanner
Every name is prefixed `arcy.` and suffixed with your environment's Token, for example `arcy.anon.`. This table is for your own configuration, not for a public policy.
| Where | Names |
| --- | --- |
| Cookies, on your registrable domain | `arcy.anon.`, `arcy.consent.` |
| `localStorage` | `arcy.shell.`, `arcy.tokens.`, `arcy.chat.`, `arcy.session.`, `arcy.flow.` |
| `sessionStorage` | `arcy.visit.`, `arcy.preview.`, `arcy.telemetry.stop.` |
Classify these as functional or necessary storage rather than analytics or advertising, and confirm that classification with your own counsel or CMP vendor. If `arcy.init()` is never called for a visitor, none of it is written. To let your CMP hear about an Accept given inside the chat, wire `arcy.onConsent()` as shown on [Consent](/settings/consent).
---
# Privacy policy paragraph
Source: https://docs.arcyai.com/legal-templates/privacy-policy
When arcy.js runs in your Product, your end users' session data is processed by ARCY AI as a sub-processor acting on your instructions, and your privacy policy needs a paragraph saying so. The block below is a starting point, not a finished document.
This is boilerplate, not legal advice. Have your own counsel review it before publishing, and adapt it to how you configured ARCY AI: which attributes you pass, whether conversation storage is on, and which flows you published.
## What to paste
```text
Third-Party Product Assistance (ARCY AI)
[Your Company Name] uses ARCY AI, a third-party service, to provide in-product
guidance, assistance, and support inside [Your Product Name]. When you use
[Your Product Name], ARCY AI's software collects certain data about your
session and interactions on our behalf, including:
- Session timestamps and the pages you visit within [Your Product Name]
- Structural details of your interactions (for example, that you clicked a
button, submitted a form, or navigated to a page), described by element
type, position, and label, not by the values you typed
- Progress through in-product guided flows, if used
- Conversation content, if you interact with the ARCY AI-powered assistant
("[Your Assistant Name]")
- An identifier and any account details we choose to share with ARCY AI
(such as [list the specific attributes you pass, e.g. plan name, role])
ARCY AI masks sensitive input (such as passwords, form field values, and
patterns resembling emails, government IDs, or payment card numbers) in your
browser before this data is transmitted. ARCY AI acts as our data processor
for this purpose and does not sell your data or use it to train its own AI
models. For details on how ARCY AI itself processes data, including your
rights to access, correct, delete, restrict, port, or object to this
processing, see ARCY AI's own Privacy Policy at https://arcyai.com/privacy
(and, for data subjects in Turkey, https://arcyai.com/kvkk).
You can ask us to disable this functionality for your account by contacting
[your support contact].
```
## Notes on filling this in
- Replace every `[bracketed]` placeholder. If the in-product assistant has no name, drop that sentence or write "the in-product assistant".
- List only the attributes you pass to `identify()`. Do not describe data you do not send.
- If **Store conversations** is off for your Product, say so, since it changes what is retained. The inventory this paragraph summarizes is on [What ARCY collects](/privacy/what-arcy-collects).
- Do not claim a certification on ARCY AI's behalf that is not complete on [Certification status](/compliance/certification-status).
- The cookies and browser storage this paragraph refers to have their own template on [Cookie policy disclosure](/legal-templates/cookie-and-storage).
---
# Sub-processor / DPA disclosure
Source: https://docs.arcyai.com/legal-templates/sub-processor-dpa
If you are the data controller for your end users and you sign data processing agreements with your own customers, you need to list ARCY AI as a sub-processor, together with ARCY AI's own sub-processors.
This is boilerplate, not legal advice. Have your own counsel review it, and request ARCY AI's own DPA before relying on it for a regulated customer relationship.
## What to paste
```text
Sub-processor: ARCY AI
Purpose: In-product user guidance, assistance, and behavioral analytics
within [Your Product Name].
Data processed: Session and interaction data described in our Privacy
Policy's "Third-Party Product Assistance" section, and any account
identifiers or attributes we choose to share with ARCY AI.
Location of processing: ARCY AI's infrastructure runs on Amazon Web
Services, in [AWS region, confirm with ARCY AI].
ARCY AI's own sub-processors are listed and kept current at
https://docs.arcyai.com/compliance/sub-processors. ARCY AI does not sell or
share sub-processor data with third parties for their own purposes. To
request ARCY AI's Data Processing Agreement or security questionnaire,
contact contact@arcyai.com.
```
## Notes on filling this in
- Ask for the AWS region through [Data processing agreements](/compliance/data-processing-agreements) before naming one. The template leaves it as a placeholder because naming the wrong region in a signed customer contract is a liability.
- Link to [Sub-processors](/compliance/sub-processors) rather than copying its table into a document you do not intend to keep updated.
- ARCY AI's GDPR posture is in progress, not certified; see [Certification status](/compliance/certification-status). If your DPA makes you represent your sub-processors' certification status, state it as it stands.
- A signed DPA with ARCY AI is available on request. If you are in a regulated industry, request it and confirm terms before relying on this disclosure in a customer contract.
---
# Data retention
Source: https://docs.arcyai.com/privacy/data-retention
| Data | Retained |
| --- | --- |
| Behavioral and autocapture events | While your Product is active |
| Conversation transcripts | 12 months |
| Images an end user attaches in chat | 30 days. The transcript row survives and reads "image removed" |
| `userId`, attributes and role | While your account is active |
| Consent answers | While your Product is active. Never pruned, so you can show what a visitor was asked and what they answered |
Retention is the same on every plan.
## Retention and the funnel window are two different numbers
Events are kept for as long as your Product is active. What ARCY works out from them, the insights, the funnels and the content gaps, is kept for as long as your workspace is open.
A funnel is walked over the last 90 days of traffic. That is a query window, not a retention window: a drop-off you look at today reflects the last 90 days, and the older events behind it are still stored.
## Deleting your data
To delete your account, email contact@arcyai.com. Deletion is completed within 30 days.
An erasure request for one named end user, under GDPR, CCPA or KVKK, is routed through you as the controller. Send it to the same address and it is completed within 30 days. State the scope in the request, the user, the environment and whether conversations are included, so we confirm it with you rather than assume it.
Deleting a Product from the dashboard destroys all of its data at once; that action is on [Product](/settings/product).
---
# What ARCY collects
Source: https://docs.arcyai.com/privacy/what-arcy-collects
ARCY runs inside your Product. Below is what arcy.js sends while it runs, so you can answer a data-inventory question and fill in your own privacy policy from it. This is the technical inventory, not the legal Privacy Policy; for the binding document, including your data-subject rights and our Children's Privacy stance, see [arcyai.com/privacy](https://arcyai.com/privacy).
Nothing below is written to a visitor's browser or sent to ARCY until the visitor has consented. The consent model and the cookies are on [Consent](/settings/consent).
## Per session
- Session start and end timestamps, and when the tab was switched away from and back. These are timestamps only, and they are what keeps "time in product" honest.
- The route a session began on, and each route change, with ids replaced and every query value dropped.
- Session context, captured once: where the visitor arrived from, campaign parameters in the address, browser and operating system, and a screen width band such as phone or laptop. Never exact screen dimensions, never a precise location, and no IP address kept as an identifier.
- Interaction events: clicks on interactive elements, navigations and form submits, described structurally by element type, position and label, never by value. This is how a flow step finds its target without you annotating your source code.
- Form field events: which field a person opened, filled or emptied again, with the field's type and whether the browser accepted the entry. Never the value typed, and never its length.
- Scroll depth as four milestones per page. Never a continuous position and never a heatmap.
- Errors: an uncaught error on the page, with its message and the script it came from, and a request that returned an error status, with its method, that status and a scrubbed URL.
- Flow events: a flow starting, each step reached and completed, the flow finishing or being left, and a step that could not run, with its reason.
- Widget and agent events: the panel opening, a conversation starting, each message sent and each answer given, an answer ARCY did not have, flows it suggested, cards clicked, a thumbs up or down, and a usage limit being hit. The message text is not on these events.
- The `userId` and the attributes you pass to `identify()`. Everything beyond the `userId` is optional; pass only the attributes you want ARCY to hold.
- Conversation text when a user talks to the agent or runs a flow, so the agent keeps context across a session and you can read the transcript. Storing it can be switched off, and what changes when you do is on [How AI request content is handled](/security/ai-request-content).
## Masked before anything leaves the browser
Input and hidden field values, and any label matching an email, a national id or a payment card pattern, are masked client-side before an event is sent. What ARCY receives is the shape of an interaction: the kind of element, roughly where, and what it is labelled.
## How a failed request is seen
A browser offers no other way to read an HTTP status, so arcy.js wraps `fetch` and `XMLHttpRequest.send` on your page. The wrapper calls your original function first and reports afterwards. It never reads a response body, so what your code receives is the object the browser made. If the wrapper cannot install, your original function stays in place. No request or response body, header or payload is collected; an event carries the method, the status and a URL scrubbed like a route.
## Never collected
- No value a user types into your Product's own fields, and not its length either.
- No session recording and no replay. A session trace is an ordered list of events, not a reconstruction of the screen.
- No DOM snapshot. A copy of your page never reaches us.
- No keystroke capture and no mouse-movement heatmap.
- No email address, password or form value you did not pass yourself as an attribute.
How long each of these is kept is on [Data retention](/privacy/data-retention).
---
# What we never do
Source: https://docs.arcyai.com/privacy/what-we-never-do
- Read or transmit your source code. ARCY never sees your repository, and there is nothing to install into your build.
- Hold a standing credential to your Product, or sign in to it.
- Take an action inside your Product that you did not author as a flow step.
- Share session data across organizations.
- Give an ARCY team member access to your production session data without a support request you opened.
- Sell or share your data with third parties.
- Use your conversation data, session data or any other customer data to train our own AI models. The model provider does not train on it either; see [How AI request content is handled](/security/ai-request-content).
---
# How AI request content is handled
Source: https://docs.arcyai.com/security/ai-request-content
Three different things happen to the content of an AI request. Separate them on a questionnaire, because the three answers differ.
**Amazon Bedrock keeps nothing.** Inference runs through Amazon Bedrock, which does not retain request content and does not use it to train foundation models. No request content leaves AWS to reach a separate AI vendor.
**ARCY's own call log holds no content.** We record what a call cost, in tokens and chats, and which model served it. The prompt and the response are not part of that record.
**Conversations are stored so you can read them.** A conversation between an end user and your assistant is kept for 12 months, so the end user can pick it up again and so you can review it in your dashboard. Every retention period is on [Data retention](/privacy/data-retention).
## Turning conversation storage off
Turn **Store conversations** off on the [Product](/settings/product) settings page. With it off, ARCY keeps only usage details for each conversation, the mode, the page and the timing, and never stores the message text or the assistant's reply.
One record survives that switch: when ARCY cannot answer a question, the fact that it failed, the reason and the time are still recorded, so the count of unanswered questions stays honest. The question text itself is not stored while the switch is off.
## Writing it into a questionnaire
Nothing is retained by Amazon Bedrock. What ARCY retains is the transcript you can see in your own dashboard, not a hidden copy of the request, and you can switch that transcript off.
---
# API key security
Source: https://docs.arcyai.com/security/api-key-security
Every environment issues its own credential pair under **Autopilot > Environments**. Creating, replacing and deleting them, and what breaks when you do, is on [Environments](/autopilot/environments).
**Token** (`arcy_pk_...`) is the public half and is designed to appear in your page source.
**Secret** (`arcy_sk_...`) is the server-side half. It exists only to sign identity verification from your backend, and it must never reach front-end code, a build variable the browser can read, a mobile binary or a repository. Where each is shown, and what replacing one breaks, is on [Environments](/autopilot/environments).
## Why a leaked Token is not a leaked allowance
A Token in a page source is expected. Before ARCY bills a chat against your allowance, the session that requested it has to have started from an origin you verified. How that check works is on [Session security](/security/session-security).
## Questionnaire answers
- Secrets are stored encrypted at rest and are never returned to a browser or written to a log in plaintext.
- Either credential can be replaced from the dashboard at any time. The consequences of each replacement are on [Environments](/autopilot/environments).
- Certification and audit status is on [Certification status](/compliance/certification-status).
---
# Infrastructure
Source: https://docs.arcyai.com/security/infrastructure
The answers a security questionnaire asks about hosting and access. For the legal Security section governing the relationship, see [arcyai.com/security](https://arcyai.com/security).
## Hosting and encryption
- ARCY runs entirely on **Amazon Web Services (AWS)**. If your organization has a data-residency requirement, ask for the region through [Data processing agreements](/compliance/data-processing-agreements) before you sign.
- All traffic between your Product, the dashboard and the ARCY backend is encrypted in transit with TLS 1.2 or higher.
- Database storage and application secrets, including your environment's Secret, are encrypted at rest.
- Database access is private and does not traverse the public internet.
- The database runs on a managed service with automated backups on a recurring schedule.
- AI inference runs through Amazon Bedrock, so request content never leaves AWS to reach a separate AI vendor. What Bedrock keeps after a call is on [How AI request content is handled](/security/ai-request-content).
- arcy.js, the script on your own page, carries no external runtime dependencies.
## Tenant isolation
Isolation is logical. Every workspace and every Product share infrastructure, and every dashboard and API request is checked against the workspace or Product that owns the data before anything is returned. The check runs on every request, never assumed from a URL or an id.
Dedicated infrastructure is not offered today. If it is a requirement for your evaluation, say so through [Data processing agreements](/compliance/data-processing-agreements).
## Who on our side can reach your data
- Access to production data and infrastructure is limited to a small team. Each person uses an individual account with MFA, never a shared credential.
- Access is granted on a least-privilege, need-to-know basis.
- Nobody on the ARCY team reads your production session data without a support request you opened.
## Incidents and status
Live system status and any ongoing incident are posted at [status.arcyai.com](https://status.arcyai.com). There is no formal incident response or breach notification commitment yet; write that into your questionnaire as it stands. Vulnerability reports go through [Responsible disclosure](/security/responsible-disclosure), and that inbox is monitored continuously.
---
# Responsible disclosure
Source: https://docs.arcyai.com/security/responsible-disclosure
If you find a vulnerability in arcy.js or the ARCY platform, email **contact@arcyai.com**.
- **Initial response:** within 48 hours.
- **Triage and resolution:** within 7 days for a confirmed issue.
Do not disclose a vulnerability publicly until we have had time to assess and patch it.
**Safe harbor.** If you make a good-faith effort to follow this policy, report through the email above, and avoid the excluded targets and methods below, we will not pursue legal action against your research.
**In scope.** The ARCY platform API, arcy.js, the sites at arcyai.com and its subdomains, authentication and authorization bypasses, cross-workspace data access, and any vulnerability caused by how ARCY configures or integrates a third-party provider, for example a misconfigured storage bucket or a broken check on a Clerk-issued identity.
**Out of scope, by target.** The platforms of our providers themselves: Amazon Web Services (AWS), Clerk, Resend, Stripe. Report a vulnerability in one of those to them, not to us. A bug in how we use one of them is always in scope.
**Out of scope, by method.** Denial-of-service testing, physical security testing, and social engineering techniques such as phishing our staff or talking a support agent into an action. A finding about a weak support or account-recovery process is welcome and in scope; describe it rather than test it against real employees or customers without our prior authorization.
---
# Session security
Source: https://docs.arcyai.com/security/session-security
ARCY serves a session only from a domain you have proven you control, and it decides which environment a call belongs to from the session itself, never from a value the caller sends. Together the two keep somebody who never touched your dashboard from spending your chat allowance. The dashboard steps for adding and verifying an origin are on [Origins](/autopilot/origins); this page is the model behind them.
## How the proof works
Proof is a DNS TXT record, the same way a certificate authority or a custom-domain feature proves ownership. For an origin such as `https://myapp.com`, ARCY issues a value unique to that origin and your Product, and you publish it as a TXT record named `_arcy-verify.myapp.com`. When you press **Verify**, the backend looks the record up and compares it.
- Proof is per hostname. `myapp.com` and `app.myapp.com` are separate origins with separate records.
- `https://myapp.com` and `https://www.myapp.com` are one origin. Verify either and both are trusted. Only a leading `www.` is folded this way.
- Proof is made once per Product and then assigned to the environments that may use it.
- Nothing is added to your source code, and the proof survives redeploys.
## What an unverified origin can and cannot do
An origin you added but have not verified is stored so you can see it is pending, and it is trusted for nothing. It does not pass CORS and it cannot start a session. A Product with no verified origin starts no session from a browser. There is no accidentally open state.
`localhost` is the one exception. It is trusted on every environment with no record, on the common development ports, so a local install works with no setup.
## Where the check runs
The origin check runs when a session starts. It is enforced on your **Primary** environment, which is where a production Token lives. Every later call, a chat message, a flow step, an event, presents the session it was issued, and the backend reads the environment and the Product from that session, never from the request body. A request cannot join your Product by guessing a session id. A refused start is recorded, so an origin that fails to start a session shows up as a verdict rather than as silence.
## When you audit a session
- A session that does not start: check that its origin shows **Verified** on Origins and is assigned to the environment whose Token the page loads.
- Chat usage you did not expect: it came from a verified origin on a session ARCY issued. Read the sessions on [Users](/autopilot/users) to find which one.
---
# Account
Source: https://docs.arcyai.com/settings/account
{/* screenshot: Settings > Account, Your profile and Workspace Profile with the save bar showing unsaved changes */}
**Settings > Account** is your own profile, the workspace profile if you are an admin, and the
two ways out of ARCY.
## Setting it up
**Your profile** is visible to every member. **Profile picture** takes a PNG, JPEG, GIF or
WebP up to 5MB, or remove it to fall back to your initials. **First name**, **Last name** and
**Department** save together through **Save changes**; the **Department** field suggests the
departments already in use. If one part of the save fails, the error names which part, and
the rest is saved.
**Email** shows your active address. Changing it sends a code to the new address; entering
the code makes it primary and removes the old one. Closing partway leaves nothing changed.
**Password**: enter your current password, the new one and its confirmation, then
**Change password**. If you signed in with Google there is no password yet, so the button
reads **Set password** and no current password is asked for. Either signs out your other
sessions; this one stays.
**Workspace Profile** renders for admins only: **Workspace logo**, **Workspace name** and a
**Slug** that follows the name until you edit it. A taken slug is refused with a message.
## What it changes
If you created the workspace, your primary email must stay on your company's domain. The
rule, and what happens to a personal address, is on
[Create your account](/getting-started/create-account).
Neither deletion can be undone, and neither has a grace period. Delete this workspace,
admins only, removes the workspace and everything in it, and every member loses access at
once; type the workspace name to confirm. Delete your ARCY account removes you from ARCY;
type your own email to confirm. Before it accepts, the card lists the workspaces where you
are the only admin, which are deleted with you, and the ones you are only removed from. A
workspace you share with another admin stays.
## See also
- [Team](/settings/team)
- [Create your account](/getting-started/create-account)
---
# Billing
Source: https://docs.arcyai.com/settings/billing
{/* screenshot: Settings > Billing, plan card with Manage subscription and the Plans section below */}
**Settings > Billing** shows the workspace's plan, price and renewal date, and is where an
admin changes plan or payment details. Every member can read it.
## Before you start
- Every plan starts with a 14-day free trial, entered through checkout. An unconverted trial
expires and the widget stops serving, so subscribe before the date the trial banner names.
- A 30-day money-back guarantee covers the first paid month, counted from the first payment.
- A workspace with no active subscription keeps its dashboard and its history. The widget does
not serve until it subscribes.
## Setting it up
The three plans are Core, Pro and Max, billed monthly, with no overage. Every
plan is the same product; they differ only in how much of it you can use.
| | Core | Pro | Max |
| --- | --- | --- | --- |
| Agent chats a month | 2,500 | 10,000 | 30,000 |
| Team seats | 3 | 10 | 25 |
| Tracked events a month | 1M | 5M | 20M |
| Raw event history | 3 months | 6 months | 12 months |
| Training Sources | 25 | 100 | 500 |
| Flows | 25 | 100 | Unlimited |
| Verified origins | 2 | 5 | 15 |
| Image uploads a month | 100 | 500 | 2,500 |
| Products | 1 | 1 | 1 |
Current prices are on the [pricing page](https://arcyai.com/pricing). **Enterprise** is the
last card in the **Plans** section: a custom chat limit, more seats, and terms agreed with
you, through **Contact sales**.
**Manage subscription** opens plan changes, payment method, past invoices and cancellation.
Nothing leaves the page.
## What it changes
- One end-user question answered is one agent chat. Micro-insights and Lift reports are work
ARCY runs on its own and never spend your allowance.
- Chats reset at the start of each billing period. When they run out, the widget pauses for
your end users until the next period, and this page shows a banner saying so. Upgrading
adds the larger plan's chats to the current period at once.
- A plan change partway through a period keeps the current chat period, so the reset date on
[Usage](/settings/usage) can differ from the renewal date shown here.
- Caps apply when you create something, never afterwards. Over a new cap, everything you
already built keeps working; only the next create is refused.
- A crawled site is one training Source whatever its page count. Raw event history is how far
back your event data stays queryable; what ARCY worked out from it is kept for as long as
the workspace is open.
## When it goes wrong
- **Your last payment failed.** Service continues while the banner is up. **Fix payment
method** opens the card form. Service stops only if the subscription ends.
- **Plan changes need an admin.** A member sees the plan but not the checkout. Ask an admin.
## See also
- [Usage](/settings/usage)
- [Limits](/settings/limits)
- [Team](/settings/team)
---
# Consent
Source: https://docs.arcyai.com/settings/consent
{/* screenshot: Settings > Product, Consent card showing the warning while a policy link is empty */}
ARCY writes nothing to a visitor's device until that visitor has accepted your own cookie
policy. There is one consent, to your policy, and the widget only needs to hear the answer.
The two policy links it shows live on the Consent card on **Settings > Product**.
## Before you start
* Your cookie policy must describe what arcy.js stores. Paste the
[cookie policy disclosure](/legal-templates/cookie-and-storage) into it.
* Save both policy links on the [Product](/settings/product) page. Until you do, the widget
links ARCY's own policy pages instead.
* Every call below needs `init()` to have run first. Called earlier, each logs a console
warning and does nothing.
## Setting it up
A visitor can say yes in two places, and both count. Your banner calls `arcy.consent(true)`
on accept and `arcy.consent(false)` on reject. A visitor who reaches for the chat with no
grant on record is asked there, in your voice, with your two links and one Accept
button. Closing the panel means "not now" and the ask returns the next time they use the
chat. There is nothing to configure per environment.
Three calls keep both sides on one answer:
```ts
consent(granted: boolean): void
consentState(): "granted" | "refused" | null
onConsent(callback: (granted: boolean) => void): () => void
```
`consentState()` returns `null` when the visitor has never answered, or answered an older
version of the disclosure and must be asked again. Use it to decide whether your banner shows.
`onConsent` fires on every change from any source and returns an unsubscribe function. It is
how an accept inside the chat reaches your CMP or Google Consent Mode.
A plain banner, on the HTML install path, which loads arcy.js asynchronously:
```html
```
Google Consent Mode, so an accept inside the chat unlocks your analytics too:
```js
arcy.onConsent((granted) => {
gtag("consent", "update", {
analytics_storage: granted ? "granted" : "denied",
})
})
```
A consent management platform. Check its state before writing to it, so the two never call
each other in a loop:
```js
cmp.onAccept(() => arcy.consent(true))
cmp.onReject(() => arcy.consent(false))
arcy.onConsent((granted) => {
if (granted && !cmp.hasConsent()) cmp.acceptAll()
})
```
In React, one client component owns `init()`, the banner and the subscription, so nothing
reads the state before the widget is ready.
## What it changes
- **Grant.** ARCY writes its anonymous id cookie and starts the session. What it writes
from then on is listed on [What ARCY collects](/privacy/what-arcy-collects).
- **Refusal.** Recorded for six months. ARCY stops speaking first: a flow whose conditions
match will not open on its own. The visitor can still reach for the chat, and the chat asks
again.
- **No answer.** A matching flow may raise the ask itself, because nobody has said no.
- **Withdrawal.** A `consent(false)` after a grant. Collection stops, every cookie and key
ARCY wrote is deleted, and the refusal is recorded. Nothing already stored on our side is
deleted; erasure is a separate request.
Calling `consent()` with the answer already on record changes nothing. There is no consent
control inside the widget's own settings sheet: your banner is where a visitor changes their
mind.
{/* screenshot: Autopilot > Users, Consent section under the table, four cards with the range picker */}
Every answer also reaches ARCY. The **Consent** section on [Users](/autopilot/users) counts
the live sessions that started in the range you pick: **Sessions**, **Sessions that
accepted** split by banner and chat, **Sessions that did not accept** split by refused and
never answered, and **Sessions the chat won back** with its share of all grants. Every
number counts sessions, not people: a device that refused holds no identifier. A **Consent**
column on the Users list and on an account's members shows each person's latest answer,
**Members accepted** on [Organizations](/autopilot/organizations) counts the members whose
latest answer is a grant, and **Consent history** on a person's page lists every answer with
the session it was given in. An anonymous visitor who refused one day and accepted another
appears there as two rows nothing can join.
## See also
- [Product](/settings/product)
- [Cookie policy disclosure](/legal-templates/cookie-and-storage)
- [Reference](/reference)
---
# Installation
Source: https://docs.arcyai.com/settings/installation
{/* screenshot: Settings > Installation, Production environment, Verify installation showing No traffic */}
**Settings > Installation** builds the install code for the environment selected in the
sidebar, with that environment's token already in it, and lists every step between "no code"
and "this environment can carry real users".
## Before you start
- The page follows the environment switcher in the sidebar. To install a different
environment, switch there first.
- The Development environment answers from any address. Production answers only for a domain
you have verified on [Origins](/autopilot/origins), and the DNS record that proves it can
take hours to spread, so add the domain early.
## Setting it up
Three steps are required:
1. Add arcy.js. Pick your framework and how you sign users in. The code
itself, and what `init()` and `identify()` do, is on the [Quickstart](/quickstart).
2. **Replace the placeholders**. This step appears only when the code you picked contains
placeholders. What each one means is on the
[Quickstart](/quickstart#replace-the-placeholders).
3. **Verify installation**. Run the check once the code is live. It watches for a session
carrying this environment's token.
Then the readiness steps, in the order you do them:
1. [Add custom attributes](/autopilot/attributes). Undeclared keys are dropped.
2. [Enforce identity verification](/autopilot/identity-verification). Not shown on the
Development environment.
3. [Verify your domain](/autopilot/origins).
4. [Train the agent](/autopilot/train).
5. [Set the persona](/autopilot/persona).
6. [Match your brand](/autopilot/customization).
7. [Set your limits](/settings/limits).
8. [Go live](/autopilot/environments). Switch the environment live and point your production
build at its token.
9. [Create your first flow](/autopilot/flows). Flows are authored on your live site, so this
comes after going live.
10. [Measure your first flow](/autopilot/flows).
Two buttons hand the page to someone else. **Copy developer instructions** copies the whole
page as one document: the install code for the framework and sign-in method you picked, the
token, and the steps after it, written for an email or a ticket. **Hand it to a coding agent**
copies the same install as a task for an agent to run in your repository.
## What it changes
A step is marked done when ARCY sees it happen, never because you clicked it. Identity
verification is the exception: you decide when the dry run is over. On the Development
environment every readiness step is optional. Once every step is done the page says so and
folds the steps shut, where you can still open them.
## When it goes wrong
The verify check names the failure:
- No traffic from this environment: open your site in another tab so arcy.js loads. The
check picks it up on its own.
- Another environment is receiving sessions: the live code carries that environment's
token. Switch the page to it, or replace the token in your code.
- Requests from an origin are refused: that origin is not verified for this environment.
Verify it on [Origins](/autopilot/origins) and assign it to the environment.
- Identity verification is failing: sessions with a wrong signature continue as
anonymous. Check the signature your server creates on
[Identity verification](/autopilot/identity-verification).
- Unknown attributes: the check lists them. They are dropped until you declare them on
[Attributes](/autopilot/attributes).
- Only localhost traffic so far: the install works, but the environment has not been
seen from a verified production origin yet.
## See also
- [Quickstart](/quickstart)
- [Environments](/autopilot/environments)
- [Origins](/autopilot/origins)
---
# Limits
Source: https://docs.arcyai.com/settings/limits
{/* screenshot: Settings > Limits, Autopilot limits card with Anonymous pool limit showing its plan default */}
**Settings > Limits** sets your own ceilings on agent chats, inside the allowance your plan
already gives you. Admins only.
## Before you start
- No limit here can go above your plan's agent chat allowance, which is always the top limit.
The allowance per plan is on [Billing](/settings/billing).
- Every field is optional. Empty means **Unlimited**, that is, nothing beyond the plan itself.
## Setting it up
**Autopilot limits** has two groups. Under **Daily**:
- **Per-user limit**: rolling 24-hour chats per identified user.
- **Anonymous per-browser limit**: rolling 24-hour chats per anonymous browser.
Under **Monthly**:
- **Organization limit**: rolling 30-day chats for the whole organization.
- **Anonymous pool limit**: rolling 30-day chats shared by every anonymous visitor. Empty
means the plan default, which is 30% of your allowance and is shown in the field.
Type whole numbers. A number above the allowance is clamped to it as you type. Save from the
bar that appears when something changes.
**Anonymous visitor redirect** takes a **Sign in page URL** and a **Sign up page URL**, both
starting with `https://`. Leave both empty to show the plain limit message.
## What it changes
- An identified user or anonymous browser at its daily limit gets a reply saying they have
reached today's limit. Nobody else is affected.
- At the organization limit the agent is hidden from the widget until the window rolls
forward. At the anonymous pool limit it is hidden for anonymous visitors only.
- With redirect pages set, the reply to a capped anonymous visitor says signing in lifts the
limit and offers those pages as buttons. The agent never moves the visitor on its own.
## See also
- [Billing](/settings/billing)
- [Usage](/settings/usage)
---
# Product
Source: https://docs.arcyai.com/settings/product
{/* screenshot: Settings > Product, Consent card with both policy links filled */}
**Settings > Product** holds the Product's identity and the switches that decide what ARCY
keeps and whether it answers at all.
## Before you start
Only an admin can change the icon, the storage switch, the policy links, deactivation or
deletion. A member sees the saved values.
## Setting it up
**Product profile**. The **Name** is required. The **Slug** appears in dashboard URLs
(`/product/your-slug/...`) and follows the name as you type until you edit it yourself;
whatever the field shows is what is saved. Lowercase letters, numbers and hyphens only. If
the slug changes on save you are moved to the new URL. The **Product icon** is a PNG, JPEG,
WEBP or SVG up to 5MB and saves the moment the upload finishes. Text changes wait for
**Save changes** in the bar that appears once something differs; **Discard** reverts them.
**Store conversations**. On by default. On, ARCY stores what users type in the widget, which
is what conversation history and insights read. Off, ARCY keeps only mode, page and timing
and never stores the message text.
**Consent**. Two links, **Privacy policy URL** and **Cookie policy URL**, both starting with
`https://`. These are the pages the widget links whenever it asks a visitor for consent or
tells them who holds what they type. Press **Update** to save. How the consent itself works,
and how your own banner is wired to it, is on [Consent](/settings/consent).
## What it changes
- Switching **Store conversations** off changes collection from that moment. Nothing already
stored is deleted by it.
- Until both policy links are saved, the widget links ARCY's own policy pages instead of
yours, and the card shows a warning until it does not have to.
- **Deactivate** stops ARCY from responding in this Product immediately, with arcy.js still
in your code. Nothing is deleted, and conversations still age out on the same schedule as
on an active Product. Reactivate any time from the same card.
Delete product is permanent. It destroys the Product and all of its data, and any site
still loading its keys stops working at once. You confirm by typing the Product's exact
name.
## See also
- [Consent](/settings/consent)
- [Environments](/autopilot/environments)
- [Data retention](/privacy/data-retention)
---
# Team
Source: https://docs.arcyai.com/settings/team
{/* screenshot: Settings > Team, member list with one Invited row and the Invite member button */}
**Settings > Team** lists everyone with dashboard access to your workspace. Your own end users
are on [Users](/autopilot/users), not here.
## Before you start
- Only an admin can invite, edit or remove. Every member can read the list and the
**Permissions** table.
- Members plus pending invitations count against your plan's seat cap. The cap per plan is
on [Billing](/settings/billing).
## Setting it up
**Invite member** asks for an **Email**, an optional **Full Name**, an optional
**Department** suggested from the departments already in use, and a **Role**. There are two
roles, **Admin** and **Member**, and the **Permissions** table on the page lists what each can
do, area by area. An invited member can use any email address.
From a row's menu, **Edit** changes that member's department. **Remove member** removes an
active member; on an invited row the same action cancels the invitation.
## What it changes
- A role is set at invite time. There is no control here to change it afterwards.
- Removing a member takes effect immediately and cannot be undone.
- At the seat cap, **Invite member** is disabled and says why. Existing members keep their
access; remove someone or change plan to invite again.
## See also
- [Billing](/settings/billing)
- [Account](/settings/account)
---
# Usage
Source: https://docs.arcyai.com/settings/usage
{/* screenshot: Settings > Usage, Plan limits with one gauge near its ceiling */}
**Settings > Usage** is where you read consumption. To cap it, go to
[Limits](/settings/limits). Admins only.
## Setting it up
There is nothing to configure. **Plan limits** shows every ceiling your plan sets and how
much of it is used, in two groups: ceilings that reset with your billing cycle (Autopilot
chats, events tracked, image uploads) and ceilings fixed by your plan (products, team seats,
training Sources, flows, verified origins). A ceiling your plan does not cap shows the count
and **Unlimited**.
**Autopilot usage** shows chats over a date range you pick, with **Chats a day** and, when
the workspace has more than one Product, **Chats by product**. **Activity** shows
**Daily activity** for the same range: sessions, events and active users, one metric plotted
at a time.
## What it changes
- The reset date for the billing-cycle group is printed above it.
- Deleting a flow, a Source or an origin frees its slot at once.
- What counts as a chat, what each plan includes, and when the ceilings reset is on
[Billing](/settings/billing).
## See also
- [Billing](/settings/billing)
- [Limits](/settings/limits)