Customization
Configure the ARCY widget's branding, modes, usage limits, and UI controls from the dashboard or via code.
ARCY lets you tailor the embedded widget to match your product. You can set a logo, a primary color, which modes are available to your users, per-mode usage limits, and which UI controls are visible. Changes made in the dashboard apply to every user of your app automatically.
Using the dashboard
Go to app.arcyai.com, select your app, and scroll to the Customization section. The card has four groups:
Theme
| Field | What it does |
|---|---|
| Logo URL | An https:// image URL displayed in the widget header. Leave blank to show no logo. Only https:// URLs are accepted. |
| Primary color | A hex color (e.g. #1a2b3c) applied to buttons and accents. Hex values only. |
Modes
| Field | What it does |
|---|---|
| Enabled modes | Which of Chat, Teach, and Agent are available to your users. At least one must be enabled. |
| Default mode | Which mode opens first. Must be one of the enabled modes. |
Usage limits
Set a per-user cap on how many times each mode can be invoked within a time window.
| Field | What it does |
|---|---|
| Max uses | Maximum invocations per user. Leave blank for no limit. |
| Per | Time window: 1 hour, 24 hours, or 7 days. |
Only enabled modes appear in this section. If you disable a mode, its limit settings are cleared.
When a user reaches their limit, the mode's send button is disabled with a brief "limit reached" message. The count resets automatically when the time window expires. Anonymous users (no userId passed to ARCYProvider) are not subject to limits.
UI controls
| Toggle | What it controls |
|---|---|
| Theme toggle | The light/dark mode switcher in the widget footer. |
| History panel | The session history list accessible from the widget header. |
| Behavior toggles | The agent autonomy controls (Ask/Auto) visible in Agent mode. |
Click Save customization to apply your changes.
For developers
You can pass customization directly as a prop on ARCYProvider. This is useful for applying per-tenant or per-user branding at runtime.
import { ARCYProvider } from "@arcyai/sdk"
import type { ArcyCustomization } from "@arcyai/sdk"
const customization: ArcyCustomization = {
theme: {
logo: "https://example.com/logo.png",
primaryColor: "#2563eb",
},
modes: {
enabled: ["chat", "teach"],
default: "chat",
},
limits: {
chat: { max: 20, windowMs: 86400000 }, // 20 per 24 hours
teach: { max: 10, windowMs: 86400000 },
},
ui: {
showThemeToggle: false,
showHistory: true,
showBehaviorToggles: false,
},
}
export default function RootLayout({ children }) {
return (
<ARCYProvider publicKey={process.env.NEXT_PUBLIC_ARCY_PUBLISHABLE_KEY!} customization={customization}>
{children}
</ARCYProvider>
)
}Merge behavior
Settings in your code always take priority over settings saved in the dashboard. The merge happens at the leaf level: if you set theme.primaryColor in code, that field is used regardless of what the dashboard has saved. Fields you do not set in code fall back to the dashboard value.
Example: if the dashboard has theme.logo set and your code sets only theme.primaryColor, both values are used. If your code sets theme.logo to a different URL, the code value wins for that field only.
ArcyCustomization type reference
interface ArcyCustomization {
theme?: {
logo?: string // https:// URL
primaryColor?: string // hex only, e.g. "#1a2b3c"
}
modes?: {
enabled?: ("chat" | "teach" | "agent")[] // at least one required
default?: "chat" | "teach" | "agent" // must be in enabled list
}
limits?: {
chat?: { max: number; windowMs: number }
teach?: { max: number; windowMs: number }
agent?: { max: number; windowMs: number }
}
ui?: {
showThemeToggle?: boolean
showHistory?: boolean
showBehaviorToggles?: boolean
}
}windowMs is a duration in milliseconds. Common values:
| Duration | Value |
|---|---|
| 1 hour | 3600000 |
| 24 hours | 86400000 |
| 7 days | 604800000 |
Common questions
What happens if the logo URL fails to load? The widget falls back to showing no logo. The rest of the widget is unaffected.
Can I use CSS color formats like rgb() or named colors for primaryColor?
No. Only hex values are accepted (e.g. #1a2b3c). Other CSS formats are not supported by the widget renderer.
What happens if default is set to a mode not in enabled?
The dashboard prevents this automatically. If you pass it via code, the widget falls back to the first mode in the enabled list.
Do usage limits apply to users without a userId?
No. Limits are tracked per userId. If no userId is passed to ARCYProvider, limits are not enforced for that session.