Configuration
All ARCYProvider props and what they control.
ARCYProvider is the root component that connects your app to ARCY. Wrap your root layout with it and pass your publishable key plus any identity props you have available.
Supported insights
ARCY's dashboard insights each need specific traits to activate. See Trait requirements for the full mapping of which insight needs which trait, on which prop.
Props
publicKey (required)
publicKey: stringYour ARCY publishable key. Safe to include in client-side code. Get it from app.arcyai.com under Settings > API Keys.
Store it in your env file and pass it via process.env or import.meta.env:
Add to .env.local:
NEXT_PUBLIC_ARCY_PUBLISHABLE_KEY=pk_live_...publicKey={(process.env.NEXT_PUBLIC_ARCY_PUBLISHABLE_KEY || process.env.NEXT_PUBLIC_ARCY_TEST_PUBLISHABLE_KEY)!}Falls back to NEXT_PUBLIC_ARCY_TEST_PUBLISHABLE_KEY when the live key isn't set, so a .env.local holding only test keys (the convention for local dev, see Quickstart) still resolves. Vite and CRA need the same value duplicated under VITE_ARCY_PUBLISHABLE_KEY/REACT_APP_ARCY_PUBLISHABLE_KEY instead, since neither framework exposes NEXT_PUBLIC_-prefixed vars to the browser.
showWidget
showWidget?: booleanWhether ARCY renders its built-in widget UI (Launcher, Panel, Overlay, ChatBar, InterventionPrompt, CopilotTooltip). Defaults to true. Set to false to hide the widget on a page (for example a sign-in screen) while the session, tracking, and detection engine keeps running unchanged underneath.
uiLanguage
uiLanguage?: "en" | "tr"Sets the widget's UI language. Defaults to "en". Setting "tr" translates all built-in widget chrome (buttons, labels, confirmations, toasts, coachmarks) to Turkish, and sets the default (non-overridden) values of customization.content's greetingMessage, assistantName, and chatPlaceholder. An explicit content override always wins over the uiLanguage default for that field. See Customization for how uiLanguage and content interact.
uiLanguage also sets the AI's default response language for Chat, Copilot, and Autopilot. The model may still answer in the end user's own language when their query is unambiguously written in the other supported language (English or Turkish), so a Turkish-configured widget doesn't force an English-speaking user into Turkish replies. Brand terms (ARCY, Chat, Copilot, Autopilot) are never translated, in either the widget UI or AI responses.
Only English and Turkish are supported today. This is a code-level prop set once in your ARCYProvider JSX, there's no dashboard control for it yet. Changing it takes effect on the widget's next session bootstrap, not mid-session.
<ARCYProvider publicKey={(process.env.NEXT_PUBLIC_ARCY_PUBLISHABLE_KEY || process.env.NEXT_PUBLIC_ARCY_TEST_PUBLISHABLE_KEY)!} uiLanguage="tr">
{children}
</ARCYProvider>userTraits
userTraits?: {
userId?: string // Your auth system's user ID for the currently logged-in user
email?: string
name?: string
plan?: string
planValue?: number // Monthly plan value, in planCurrency. Drives revenue insights
planCurrency?: PlanCurrency // ISO 4217 code planValue is in. Defaults to USD
role?: string
signupDate?: string | Date // When this user signed up. Renamed from createdAt.
persona?: string // Job-function classification, used for segmentation. Distinct from role.
region?: string // Geography, used for segmentation
billingCycle?: number // Billing cadence in days
renewalDate?: string | Date // Next auto-renewal date (B2C)
// Extra data about this user
seatCount?: number // Active seats/licenses this user holds
[key: string]: string | number | boolean | null | undefined | Date
}Traits used for segmentation and revenue tracking. All fields are optional. More traits give ARCY more signal for behavioral analysis.
userId is the one trait ARCY extracts specially (pulled into the session bootstrap payload to tie behavioral signals to this user in your dashboard); every other trait stays opaque pass-through data. Omit it (don't pass null) when no user is signed in. There is no separate root-level userId prop — pass it here, nested under userTraits.
The user's role within your app (e.g. "admin", "viewer") also lives here. Used in the dashboard to segment sessions by role.
The planValue field is the monthly value of this user, denominated in planCurrency. When provided, it activates Revenue at risk and Recoverable now in the Console. See Revenue Tracking for the full setup and the B2C vs. B2B guidance.
planCurrency is the ISO 4217 code that planValue is expressed in. That account's own figures still render when it's omitted (assumed USD), but the account is excluded from the portfolio-wide Revenue at risk / Recoverable now totals rather than silently counted as USD there. Set it explicitly on every account you want counted. Supported values: USD, EUR, GBP, JPY, CNY, AUD, CAD, CHF, INR, TRY. ARCY never converts between currencies, so keep planValue in a single currency per user.
plan alone (without planValue) does not activate Revenue at risk. plan is a display label; planValue is the number ARCY sums.
createdAt was renamed to signupDate to avoid ambiguity with a database row's creation timestamp. featureDepth was removed entirely (it never worked correctly server-side); there is no replacement.
The seatCount field is additional account-sizing data ARCY uses for segmentation.
Every dashboard insight declares which of the traits above it needs, and whether they're required or optional. See Trait requirements for the full mapping. ARCYProvider reads this same mapping to print a console warning in development when a required trait for an active insight is missing, naming the exact prop path to add.
organizationTraits
organizationTraits?: {
organizationId?: string // Your auth system's organization or workspace ID
name?: string
plan?: string
planValue?: number // Monthly plan value, in planCurrency (the account MRR)
planCurrency?: PlanCurrency // ISO 4217 code planValue is in. Defaults to USD
signupDate?: string | Date // When this organization signed up
contractEndDate?: string | Date // Fixed-term contract end date (B2B)
billingCycle?: number // Billing cadence in days
region?: string // Geography, used for segmentation
// Extra data about this organization
companySize?: "1-10" | "11-50" | "51-200" | "201-500" | "500+"
industry?: string
seatCount?: number // Active seats/licenses under this org
integrationCount?: number // Integrations connected by this org
[key: string]: string | number | boolean | null | undefined
}Account-level traits for segmentation and revenue tracking, for B2B SaaS products.
organizationId is the one trait ARCY extracts specially (pulled into the session bootstrap payload to link this user to an account in your dashboard); every other trait stays opaque pass-through data. There is no separate root-level organizationId prop — pass it here, nested under organizationTraits.
For B2B products, set planValue on organizationTraits to track account-level MRR. It powers Revenue at risk and Recoverable now in the Console. See Revenue Tracking.
Set planCurrency on organizationTraits to control the currency the account's MRR renders in, and to include this account in the portfolio-wide revenue totals (an account with planValue but no planCurrency renders its own MRR as USD but is excluded from those totals). It accepts the same ISO 4217 codes listed for userTraits.planCurrency above.
If you bill per seat, aggregate your own seat-level pricing into a single organizationTraits.planValue before passing it. ARCY does not sum userTraits.planValue across an organization's members into an account figure.
renewalDate (on userTraits, B2C) and contractEndDate (on organizationTraits, B2B) are deliberately separate fields for different renewal semantics, not the same date with two names.
The companySize and industry fields describe your account's firmographics, and seatCount and integrationCount describe its size and integration footprint. ARCY uses all four for segmentation.
There is no metadata prop. Both userTraits and organizationTraits have an open index signature, so any extra data you want ARCY to have goes directly on whichever one it actually describes — user-scoped data on userTraits, org-scoped data on organizationTraits. Attribute it to the right subject rather than passing it as unattributed metadata.
<ARCYProvider
publicKey="pk_..."
userTraits={{ userId }}
organizationTraits={{
organizationId: orgId,
name: "Acme Corp",
plan: "enterprise",
companySize: "51-200",
industry: "FinTech",
seatCount: 120,
integrationCount: 8,
}}
>
{children}
</ARCYProvider>flowAbandonThresholdMs
flowAbandonThresholdMs?: numberHow long (in milliseconds) ARCY waits before marking an in-progress guided flow as abandoned. Defaults to 300000 (5 minutes). Increase this for flows with long natural pauses between steps, such as multi-step configuration wizards.
Full example
"use client"
import { ARCYProvider } from "@arcyai/sdk/react"
import "@arcyai/sdk/styles"
interface ArcyWrapperProps {
userId?: string | null
userEmail?: string | null
userPlan?: string | null
organizationId?: string | null
children: React.ReactNode
}
export function ArcyWrapper({
userId,
userEmail,
userPlan,
organizationId,
children,
}: ArcyWrapperProps) {
return (
<ARCYProvider
publicKey={(process.env.NEXT_PUBLIC_ARCY_PUBLISHABLE_KEY || process.env.NEXT_PUBLIC_ARCY_TEST_PUBLISHABLE_KEY)!}
userTraits={{
userId: userId ?? undefined,
email: userEmail ?? undefined,
plan: userPlan ?? undefined,
}}
organizationTraits={{ organizationId: organizationId ?? undefined }}
>
{children}
</ARCYProvider>
)
}How ARCYProvider receives identity
Pass userTraits={{ userId, ...other traits }} directly as a prop. The values should come from your auth system, read server-side (for Next.js App Router) or from a client auth hook (for Pages Router or client-only setups).
Read identity server-side and pass it as props to a client wrapper:
import { auth } from "@clerk/nextjs/server"
import { ArcyWrapper } from "@/components/arcy-wrapper"
export default async function RootLayout({ children }: { children: React.ReactNode }) {
const { userId } = await auth()
return (
<html lang="en">
<body>
<ArcyWrapper userId={userId}>{children}</ArcyWrapper>
</body>
</html>
)
}Read identity from a client auth hook inside the wrapper:
import { useUser } from "@clerk/clerk-react"
import { ARCYProvider } from "@arcyai/sdk/react"
function ArcyWrapper({ children }: { children: React.ReactNode }) {
const { user } = useUser()
return (
<ARCYProvider
publicKey={(process.env.NEXT_PUBLIC_ARCY_PUBLISHABLE_KEY || process.env.NEXT_PUBLIC_ARCY_TEST_PUBLISHABLE_KEY)!}
userTraits={
user?.primaryEmailAddress
? { userId: user?.id ?? undefined, email: user.primaryEmailAddress.emailAddress }
: undefined
}
>
{children}
</ARCYProvider>
)
}See CLI commands for the full .arcy/ setup flow across all auth libraries.