Configuration Reference

Every environment variable AVA reads, grouped by area, with its type, default, whether it is required, and what it changes. The authoritative template is .env.example in the repo root — this document explains it.

How config is loaded. In development the custom server loads .env.local from the repo root (with override: true, so .env.local wins over shell vars). In the container, your env file is mounted read-only at /app/.env.local and docker-entrypoint.sh validates the required set before the server starts. Almost every non-NEXT_PUBLIC_* value is read at call time, so you can change it and restart the container with no rebuild.

Two special cases:

  • NEXT_PUBLIC_* variables are compiled into the browser bundle at build time (Dockerfile build args). Changing them requires a rebuild, not just a restart.
  • AUTOTASK_API_SECRET is read raw from the env file (bypassing dotenv variable-expansion) because it commonly contains $. Wrap it in double quotes.

Legend: Required = the container refuses to start without it (or it is required for the configured AI provider). Recommended = boots without it but you should set it for a correct deployment. Optional = safe default.


Required to boot

These are validated by docker-entrypoint.sh; a missing one aborts startup with a clear error naming the variable.

VariableTypeEffect
NEXTAUTH_SECRETstring (32+ chars)Signs the engineer session cookie and client session tokens (HS256, 24 h). Generate with openssl rand -base64 48.
AUTOTASK_API_USERstring (email)AutoTask API-only user.
AUTOTASK_API_SECRETstringAutoTask API secret. Quote it (may contain $).
AUTOTASK_API_INTEGRATION_CODEstringAutoTask API tracking integration code.
AUTOTASK_API_ZONE_URLURLYour AutoTask REST zone base. Trailing slash optional; /V1.0 appended if absent.
AZURE_AD_CLIENT_IDGUIDEntra app registration client ID.
AZURE_AD_CLIENT_SECRETstringEntra app registration client secret.
AZURE_AD_TENANT_IDGUIDEntra directory (tenant) ID.
ENGINEERING_GROUP_IDGUIDEntra security-group object ID; only members may sign in (checked against the groups claim, fail-closed).
RECAPTCHA_SECRET_KEYstringreCAPTCHA v3 server-side secret.
SMTP2GO_USERstringSMTP2GO username.
SMTP2GO_PASSWORDstringSMTP2GO password.
SUPPORT_FALLBACK_EMAILemailRecipient for the after-hours "email a ticket" fallback form. No vendor default — AVA never falls back to a built-in address, so the container refuses to start without it.
AI provider keystringThe key for whichever provider LLM_FAST / LLM_QUALITY use — see AI / LLM providers. With defaults, this is ANTHROPIC_API_KEY.

NEXTAUTH_SECRET strength checks

Beyond mere presence, the entrypoint enforces secret quality at boot:

  • Shorter than 32 characters → startup aborts. This secret signs every engineer and client session, so it must be long and random.
  • Placeholder-looking values are refused (for example anything containing changeme) — a value copy-pasted from documentation cannot reach production.

Generate a real one:

openssl rand -base64 48

The entrypoint also warns (without failing) if the mounted env file is group- or world-readable — it holds live secrets, so keep it chmod 600.


AutoTask — default ticket values

Picklist IDs are specific to your AutoTask instance; discover them with npx tsx scripts/discover-picklists.ts. Do not copy another instance's numbers.

VariableTypeDefaultReq.Effect
AUTOTASK_DEFAULT_TICKET_STATUSint1RecommendedStatus ID for new chat tickets ("New").
AUTOTASK_DEFAULT_TICKET_PRIORITYint3RecommendedFallback priority ID ("Normal").
AUTOTASK_DEFAULT_TICKET_QUEUE_IDint—RecommendedHelpdesk queue the ticket lands in.
AUTOTASK_DEFAULT_TICKET_SOURCEint—RecommendedTicket "source" ID (create a "Chat" source in AT if needed).
AUTOTASK_DEFAULT_TICKET_TYPEint—RecommendedTicket type for chat-originated tickets.
AUTOTASK_PRIORITY_P1int(falls back to AUTOTASK_DEFAULT_TICKET_PRIORITY, then 3)RecommendedAT priority ID mapped from triage P1 (critical).
AUTOTASK_PRIORITY_P2int(falls back to AUTOTASK_DEFAULT_TICKET_PRIORITY, then 3)RecommendedAT priority ID mapped from triage P2 (high).
AUTOTASK_PRIORITY_P3int(falls back to AUTOTASK_DEFAULT_TICKET_PRIORITY, then 3)RecommendedAT priority ID mapped from triage P3 (normal).
AUTOTASK_PRIORITY_P4int(falls back to AUTOTASK_DEFAULT_TICKET_PRIORITY, then 3)RecommendedAT priority ID mapped from triage P4 (low).
AUTOTASK_NOTE_PUBLISH_EXTERNALint1RecommendedThe publish value for the client-facing close note. Per-instance picklist — 1 = "Internal Only" is universally valid; only change to a value your instance defines, or the note post fails with a 500.

⚠️ Warning — the four priority vars are not a graduated default. There is no built-in per-priority-level mapping. Each of AUTOTASK_PRIORITY_P1..P4 resolves independently: if a given Pn is unset, it falls through to the single shared AUTOTASK_DEFAULT_TICKET_PRIORITY, and if that is also unset, to a hardcoded 3. If you do not set these four vars, ALL AI-triaged chats file at the same AT priority, regardless of what the AI determined — P1/critical and P4/low tickets become indistinguishable in AutoTask. Discover your instance's priority picklist IDs with npx tsx scripts/discover-picklists.ts and set all four.

Priority editing in the engineer console (v1.8.0). Engineers can change a ticket's priority from the chat's ticket panel or with /priority. That is only enabled when all four of AUTOTASK_PRIORITY_P1..P4 are set and pairwise distinct, and every one of the four IDs is an active value of your live AT priority picklist — otherwise AVA cannot tell which AT priority a P-level means (or AT would refuse the write), so the Priority field is read-only (hint: "Priority editing isn't configured — ask your administrator") and AVA refuses priority changes instead of writing a guessed value. A typical mapping, using your own picklist IDs:

AUTOTASK_PRIORITY_P1=4   # your "Critical" priority id
AUTOTASK_PRIORITY_P2=1   # your "High" priority id
AUTOTASK_PRIORITY_P3=2   # your "Medium" priority id
AUTOTASK_PRIORITY_P4=3   # your "Low" priority id

A priority change also updates the chat's P-level in the queue and header. Status editing needs no config: the status list is read live from your AT picklist, and "Complete" is never offered there (tickets are completed through the wrap-up flow). Complete is recognised by its label and by its picklist ID — AT's system value 5 — so a renamed or localized Complete status is still refused; if your instance's Complete status uses a different ID, set AUTOTASK_COMPLETE_STATUS_ID (below).

Engineer internal notes & ticket edits (v1.8.0)

VariableTypeDefaultReq.Effect
AUTOTASK_NOTE_PUBLISH_INTERNALpositive int1RecommendedThe publish value for every engineer-only AT note: live internal notes, the close-time "Chat Transcript", the "Chat internal notes (not synced live)" note and the wrap-up internal note. Must be an Internal-Only value on your instance — verify it with the TicketNotes entityInformation/fields check in autotask-setup.md (Step 7, "Internal notes"). An invalid value logs one warning and falls back to 1.
AUTOTASK_SYNC_INTERNAL_NOTESbooltrueOptionalLive sync of engineer internal notes to the AT ticket. Set false and notes are kept in AVA and reach AT only at close (in the "not synced live" note and the transcript). Use this if an AT workflow rule would email the contact when a note is added.
AUTOTASK_WEB_URLhttps URLderived from AUTOTASK_API_ZONE_URLOptionalOrigin of your AutoTask web UI, used for ticket deep links in the engineer console. Only https: is accepted and only the origin is kept. When unset, AVA derives it from the API zone (webservicesN.autotask.net → https://wwN.autotask.net); if neither works, ticket numbers render as plain text. Copy webUrl from the zoneInformation call (autotask-setup.md, Step 3).
AUTOTASK_COMPLETE_STATUS_IDnon-negative int5OptionalPicklist ID of your AT "Complete" ticket status. The console never lets an engineer set it mid-chat (wrap-up completes the ticket); it is matched by this ID as well as by the label "Complete". An invalid value falls back to 5.
TICKET_WRITE_RATE_LIMIT_PER_MINpositive int10OptionalPer-engineer limit (per minute) on ticket status/priority writes from the console (ticket panel, /status, /priority). Excess writes get "Slow down". An invalid value (including 0) logs a warning and uses 10.

Internal notes are never shown to the client — not in the chat, not in emails, not in the client-facing AT note, the resolution field or the time entry. AutoTask workflow rules still apply to every write AVA makes, so read the workflow-rule caution in autotask-setup.md (Step 7, "Workflow rules and the engineer console") before go-live. How these features look to engineers is covered in engineer-console.md.

Resource role ID — AUTOTASK_DEFAULT_ROLE_ID

VariableTypeDefaultReq.Effect
AUTOTASK_DEFAULT_ROLE_IDpositive int(built-in fallback)Set itResource role ID used when assigning a ticket to the accepting engineer and when posting the billed time entry on close.

Resolution is warn-not-fail: if unset — or set to something that isn't a positive integer — AVA logs a one-time warning and falls back to a built-in role ID that will not match your AutoTask instance. Role IDs are per-instance, so always set your own (find them with GET /Roles or via your AT admin's Roles list). An invalid value never blocks startup; it just degrades to the fallback — which would post time entries under a role your instance doesn't recognize.

Catchall company — AUTOTASK_CATCHALL_COMPANY_ID

VariableTypeDefaultReq.Effect
AUTOTASK_CATCHALL_COMPANY_IDint (AT company ID)(unset)RecommendedCompany that receives tickets from email domains not tied to any AT company (personal Gmail, etc.).

If unset, unknown-domain chats start without an AutoTask ticket and fall into a degraded recovery path (late ticket creation at close, or an engineer-confirmed close-without-sync). Set it to avoid that path entirely. Note 0 is a valid AutoTask company ID — AVA treats "unset" and "0" differently, so an explicit 0 does enable the catchall. Find a company's ID with npx tsx scripts/test-autotask.ts <domain>.


Microsoft Entra ID

VariableTypeDefaultReq.Effect
AZURE_AD_CLIENT_IDGUID—RequiredApp registration client ID.
AZURE_AD_CLIENT_SECRETstring—RequiredApp registration client secret.
AZURE_AD_TENANT_IDGUID—RequiredTenant ID (forms the MSAL authority URL).
AZURE_AD_REDIRECT_URIURLhttp://localhost:3000/api/auth/callbackRecommendedOAuth callback; must match the app registration exactly. In production set it to https://<your-chat-domain>/api/auth/callback.
ENGINEERING_GROUP_IDGUID—RequiredSecurity-group object ID; sign-in requires membership (fail-closed if the groups claim is missing or malformed).

AI / LLM

AVA's AI layer (triage, similar-resolution suggestions, trend summaries, field summarization, the engineer /draft / /rewrite / /summarize commands, and the close-flow ticket summary) is provider-agnostic: it runs on the Vercel AI SDK behind two role-based model slots, LLM_FAST and LLM_QUALITY, supporting Anthropic (default), OpenAI, Google Gemini, and OpenRouter.

The full reference — provider matrix, provider/model string format, conditional key requirements, which features use which tier, and the timeout caveat — lives in ai-providers.md. Quick summary:

VariableDefaultNotes
LLM_FASTanthropic/claude-haiku-4-5-20251001Triage, suggestions, trends, field summarization, engineer AI commands.
LLM_QUALITYanthropic/claude-sonnet-4-6Final ticket summary.
ANTHROPIC_API_KEY / OPENAI_API_KEY / GOOGLE_GENERATIVE_AI_API_KEY / OPENROUTER_API_KEY—Only the key(s) for the provider(s) you actually reference are required.
ANTHROPIC_TIMEOUT_MS15000Per-call AI timeout — applies to all providers despite the name.

Engineer AI cost guard (v1.8.0)

The engineer-console AI commands (/draft, /rewrite, /summarize, the wrap-up Summarize and "Draft all" buttons, similar resolutions and trends) share an in-memory budget. Client-side AI triage is not counted (it is rate-limited per IP instead).

VariableTypeDefaultEffect
AI_MAX_CALLS_PER_SESSIONint ≥ 030AI calls allowed per chat. 0 disables the per-chat AI commands (they are greyed out).
AI_MAX_CALLS_PER_ENGINEER_PER_HOURint ≥ 060AI calls per engineer in a fixed one-hour window. 0 disables all engineer AI; the AI commands are greyed out.

Only one call per command per chat runs at a time (a double-click is refused). Counters reset when the container restarts. Each call writes one [ai-usage] log line with ids, model, token counts, latency and outcome — never the prompt or the output — so you can track spend from your logs. With the defaults and a Haiku-class fast model (~6k input + 350 output tokens per call), the worst case is roughly $0.25 per chat and $0.50 per engineer-hour. Invalid values log a warning and use the default.


Application & networking

VariableTypeDefaultReq.Effect
NEXT_PUBLIC_APP_URLURL(build arg)RequiredPublic app URL. Pins the Socket.io CORS origin (server hard-fails in production if unset) and is baked into the client bundle. Build-time.
NEXT_PUBLIC_SOCKET_URLURL (wss://)(build arg)RequiredWebSocket URL the client connects to. Build-time.
NEXT_PUBLIC_RECAPTCHA_SITE_KEYstring(build arg)RequiredreCAPTCHA v3 site key (public by design). Build-time.
NODE_ENVproduction|developmentproduction (image)OptionalStandard Node environment. The image sets production.
PORTint3000OptionalListen port.
DATABASE_URLlibsql/SQLite URLa SQLite file in the repo root (local) / on the data volume under /app/data/ (image)OptionalSQLite database location. The image points it at the data volume; override only if you relocate the DB.

Trusted proxy — NGINX_TRUSTED_PROXY

VariableTypeDefaultReq.Effect
NGINX_TRUSTED_PROXY1(unset — never trust)Set 1 behind your proxyWhether AVA trusts X-Forwarded-For / X-Real-IP when determining the real client IP for per-IP rate limiting.

Trust is opt-in only. Set it to exactly 1 when — and only when — the app always sits behind your own reverse proxy (as in the provided compose + nginx templates, where nginx sets the header from the actual connection address). Any other value — including unset, and even with NODE_ENV=production — means the header is ignored. When multiple comma-separated hops are present, AVA uses the entry appended by the proxy nearest to it.

If you forget it behind a proxy: AVA can't tell visitors apart, so every visitor shares one set of per-IP limits (chat starts, uploads) and clients start hitting "too many sessions" together. Behind the template nginx, always set NGINX_TRUSTED_PROXY=1.


Bot protection & email

VariableTypeDefaultReq.Effect
RECAPTCHA_SECRET_KEYstring—RequiredreCAPTCHA v3 server-side secret (siteverify).
RECAPTCHA_DEV_BYPASStrue(unset — fail closed)Optional (dev only)See below. Refused in production.
SMTP2GO_HOSThostmail.smtp2go.comOptionalSMTP2GO host.
SMTP2GO_PORTint2525OptionalSMTP2GO port.
SMTP2GO_USERstring—RequiredSMTP2GO username.
SMTP2GO_PASSWORDstring—RequiredSMTP2GO password.
SMTP2GO_FROMemail(none — fail closed)Set itSender address on all outbound mail. No vendor default: when unset, every email-sending route fails closed — the send is skipped and the route returns an error rather than mailing from a placeholder address. Set it to an address on your own domain.
WEEKLY_REPORT_TOKENstring(unset)OptionalBearer token guarding the weekly-survey-report cron endpoint. Generate with openssl rand -hex 32; required only if you wire up that cron.

Recipient addresses

VariableTypeDefaultReq.Effect
SUPPORT_FALLBACK_EMAILemail(none)Required to bootRecipient for the after-hours "email a ticket" fallback (listed in Required to boot).
FEEDBACK_EMAILemail(none — fail closed)OptionalRecipient for engineer feedback. When unset, the feedback route fails closed: it skips the send and logs an error — it never falls back to a vendor address.
REPORTS_EMAILemail(none — fail closed)OptionalRecipient for the weekly survey report. Same fail-closed contract as FEEDBACK_EMAIL.

reCAPTCHA verification behavior

reCAPTCHA verification is fail-closed by default everywhere: a missing secret, a missing token, a network error reaching Google, or a low score all reject the request.

RECAPTCHA_DEV_BYPASS is the one narrow escape hatch, for development and test environments only. It fails open (allows the request) when — and only when — both hold:

  • NODE_ENV is not production, and
  • RECAPTCHA_DEV_BYPASS is set to exactly true (not 1, not yes).

In production it is refused outright — when NODE_ENV=production, no value of this variable can re-enable the bypass; verification always fails closed. Leave it unset everywhere except a local dev box that has no real reCAPTCHA key. The siteverify call also enforces an outbound timeout (RECAPTCHA_TIMEOUT_MS, below) so a hung Google endpoint cannot stall the request.


File uploads

Chat participants (client and engineer) can attach files to a session. The constraints, all enforced server-side:

  • Per-file size cap: 5 MB (fixed). Larger files are rejected with HTTP 413.
  • Type allowlist: PNG, JPEG, GIF, HEIC, PDF, XLSX, DOCX, EML, ZIP, TXT, CSV.
  • Content check: a file's content must match the type it claims. Files are stored under generated names; images display inline, and every other type downloads as an attachment.
  • Access: clients can only open their own chat's attachments; an active chat's attachments are visible to the engineer handling it, and a closed chat's attachments to any signed-in engineer (Archives).

Upload budget, quota & retention

All optional; defaults shown. Invalid values warn once and fall back to the default.

VariableTypeDefaultEffect
UPLOAD_MAX_PER_IP_PER_HOURpositive int30Per-IP upload budget per hour (HTTP 429 when exceeded).
UPLOAD_TOTAL_MAX_BYTESpositive number (bytes)2147483648 (2 GB)Disk ceiling across all sessions' uploads combined. A new upload that would exceed it is rejected with HTTP 507.
UPLOAD_RETENTION_ENABLEDbooltrueScheduled retention job that deletes a closed session's upload directory once it ages past the window below — regardless of whether the files made it into AutoTask. Set exactly false to disable.
UPLOAD_RETENTION_DAYSpositive int30Retention window in days.
UPLOAD_RETENTION_INTERVAL_HOURSpositive number (may be fractional)6How often the retention job runs (in-process interval — no external cron needed).

Business hours

All optional; the defaults reproduce Mon–Fri 6 AM–6 PM Pacific. Invalid values validate-and-fall-back (they never throw). The configured schedule also drives the client-facing availability copy — the off-hours message quotes your actual hours, not a hardcoded string.

VariableTypeDefaultEffect
BUSINESS_HOURS_BYPASSboolfalseExactly true ignores the schedule entirely (chat always "open"). Testing only — set false for real clients.
BUSINESS_HOURS_TZIANA TZAmerica/Los_AngelesTimezone the open/close hours are evaluated in. Invalid zone names warn once and fall back.
BUSINESS_HOURS_OPENint 0–236Opening hour (local to BUSINESS_HOURS_TZ).
BUSINESS_HOURS_CLOSEint 0–2318Closing hour.
BUSINESS_HOURS_DAYSCSV of 1–7 (ISO, 1=Mon)1,2,3,4,5Open days.

White-label / branding

AVA ships vendor-neutral: with none of these set, the app presents as a generic "Your Company" deployment with no phone number and no client-portal link. Every deploying MSP sets its identity here. All values are read at call time — set them in your runtime env file and restart; no rebuild. See white-label.md for the full walkthrough, worked example, and verification checklist.

VariableTypeDefaultEffect
COMPANY_NAMEstringYour CompanyFull display name across the UI (page metadata, contact form, dashboard).
COMPANY_DESCRIPTORstringIT SupportDescriptor appended after the company name in prose — the page metadata description and the AI summary prompt (<COMPANY_NAME> <COMPANY_DESCRIPTOR>).
COMPANY_MONOGRAMstring (≤4 chars)AVADashboard rail tile monogram (silently truncated to 4 characters).
COMPANY_TAGLINEstringPowered by AVAFooter identity line on the client page and dashboard.
WELCOME_MESSAGEstring(neutral greeting — see below)System greeting posted at session start. Default: "Welcome to Tech Support! Your session has been created and an engineer will be with you shortly. …" including the recorded-conversation and no-passwords notices.
SUPPORT_PHONEstring(unset — hidden)Displayed support phone. When unset or empty, every phone element (banner, contact form, off-hours copy, timeout overlay) is hidden and prose adjusts. When set, a tel: href is derived automatically (bare 10-digit numbers get +1; +-prefixed international numbers pass through).
AT_CLIENT_PORTAL_URLURL(unset — plain ticket number)Base URL for client-portal ticket links. When unset or empty, the UI shows a plain ticket number instead of a link.
LOGO_PATHpublic path/ava-logo.svgPublic path of the brand logo shown on the client page and dashboard mobile bar. An empty value falls back to the default. The file must exist under public/ in the built image.
DISPLAY_TZIANA TZ→ BUSINESS_HOURS_TZ → America/Los_AngelesTimezone for all human-facing timestamps (message times, day dividers, transcript, wrap-up/billing draft). Invalid zones warn once and fall back.
COMPANY_PROFILEstringa managed service provider (MSP) supporting business clientsClientele description injected into the AI triage prompt to sharpen classification (e.g. an MSP serving medical and dental practices).

Recipient/sender addresses (SUPPORT_FALLBACK_EMAIL, FEEDBACK_EMAIL, REPORTS_EMAIL, SMTP2GO_FROM) are part of the same identity surface but are documented under Bot protection & email since they carry required/fail-closed semantics.


Session limits

VariableTypeDefaultEffect
MAX_ACTIVE_SESSIONSint 1–102Per-engineer concurrent active-chat cap. Out-of-range/invalid values warn and fall back to 2.

External-call timeouts

All optional; defaults shown. Milliseconds.

VariableTypeDefaultEffect
AUTOTASK_TIMEOUT_MSint (ms)15000Per-request AutoTask REST timeout.
SMTP_TIMEOUT_MSint (ms)10000SMTP connect + socket timeout.
RECAPTCHA_TIMEOUT_MSint (ms)10000reCAPTCHA siteverify fetch timeout.
ANTHROPIC_TIMEOUT_MSint (ms)15000AI per-call timeout (all providers) — see ai-providers.md.

NinjaOne (optional, read-only device glance)

Off by default. With NINJAONE_BASE_URL / NINJAONE_CLIENT_ID / NINJAONE_CLIENT_SECRET unset, the feature is completely dormant — the engineer dashboard's client-context panel behaves byte-for-byte as if it didn't exist (no Device section renders, no NinjaOne network calls are ever made). Set all three to turn it on.

What it does. When a client starts a chat, AVA tries to identify their machine and shows the engineer a read-only "device at a glance" card in the chat's context panel — online/offline status, last boot, disk free, pending/failed OS patches, antivirus state, public/private IP, make/model/RAM, last logged-on user, and recent alerts — plus a one-click "Open in NinjaOne" deep link to the device's dashboard page. It never modifies anything: the NinjaOne API credential is scoped to monitoring only, and the NinjaOne client exposes GET requests exclusively. Two resolution paths work independently of each other:

  • AutoTask-only baseline (no NinjaOne credentials needed). If your AutoTask instance already syncs NinjaOne data onto Configuration Items (the NinjaRMM-RemoteUrl / -BackgroundUrl / -Antivirus / -PrivateIpAddress / -DeviceUID UDFs), AVA matches the chat's AutoTask company + reported hostname to a Configuration Item and shows those UDF facts plus the deep link parsed out of the remote-URL UDF — even with NINJAONE_* fully unset.
  • Live NinjaOne API layer (optional, adds live telemetry). When the three vars above are set, AVA additionally queries the NinjaOne API directly for live device data and can fall back to a hostname/user search when no Configuration Item matched.

Create the API client (NinjaOne admin)

  1. In NinjaOne: Administration → Apps → API → Client App IDs → Add.
  2. Platform: API Services (machine-to-machine).
  3. Scope: Monitoring only — do not grant management or any write scope. This is a least-privilege design choice, not just a convention: the resulting credential cannot modify a device, run a script, or trigger an action at all.
  4. Grant type: Client Credentials. No redirect URI is needed (this is a server-to-server, not an interactive OAuth flow).
  5. Copy the generated Client ID and Client Secret into your env (below).

Env vars

VariableTypeDefaultReq.Effect
NINJAONE_BASE_URLURL(unset)Required to enableYour NinjaOne region's API base URL — see Region base URLs below. Trailing slash optional.
NINJAONE_CLIENT_IDstring(unset)Required to enableThe Client App ID from the step above.
NINJAONE_CLIENT_SECRETstring(unset)Required to enableThe Client App secret. Quote it in your env file — read via the same raw-file mechanism as AUTOTASK_API_SECRET, so a value containing $ or other shell-special characters is safe.
NINJAONE_TIMEOUT_MSint (ms)15000OptionalPer-request timeout for NinjaOne API calls.
NINJAONE_ENRICH_TICKETSboolfalse (unset)OptionalSole enable switch for AT ticket writes — attaches the resolved Configuration Item (configurationItemID) and, when available, the NinjaRMM-DeviceUID UDF, on any chat that resolves a device at high confidence. Read-only device glance itself is unaffected either way — this only gates the best-effort write-back onto your AutoTask ticket. Do not set this to true until you have run the UDF merge pre-flight against your own AutoTask instance — see below.

All three required vars must be set together — the feature is all-or-nothing. NINJAONE_ENRICH_TICKETS is independent of those three and defaults to off even when they're set.

UDF merge pre-flight (before enabling NINJAONE_ENRICH_TICKETS)

AT's PATCH /Tickets handling of the userDefinedFields array is instance-dependent: some configurations merge the array, others could blank UDFs the PATCH omits. Before flipping the flag on, verify your instance merges:

  1. Create a throwaway scrap ticket in AutoTask.
  2. Seed two different UDFs on it with known values.
  3. PATCH the ticket updating only one of the two UDFs.
  4. Confirm the other UDF survives untouched.

Only enable NINJAONE_ENRICH_TICKETS=true after step 4 passes. Another instance's pre-flight result does not transfer to yours.

Region base URLs

Use the same NinjaOne data-center region your admin console login URL shows:

RegionNINJAONE_BASE_URL
Americas (default/US)https://app.ninjarmm.com
Americas 2https://us2.ninjarmm.com
Canadahttps://ca.ninjarmm.com
Europehttps://eu.ninjarmm.com
Oceaniahttps://oc.ninjarmm.com

Systray URL setup — auto-identifying the client's machine

AVA resolves "which machine is this?" most reliably when the client reaches the chat page via a link that carries systray-substituted hints. NinjaOne's systray custom URL items support ${HOSTNAME} / $USERNAME / ${DOMAIN} placeholders, substituted at click time. In your NinjaOne branding/systray policy, set the chat link to:

https://<your-chat-domain>/?host=${HOSTNAME}&user=$USERNAME&domain=${DOMAIN}

AVA captures these once on page load, forwards them with the chat-start request, and stores them on the session as display + lookup hints only — never an authorization signal. Omitting the query string entirely still works; the device card simply has less to search on (falls back to a user/email-based search when NinjaOne is configured, or shows a "no managed device matched" empty state otherwise).

Validate your setup

npx tsx scripts/test-ninjaone.ts [hostname]

Confirms config presence, exercises the real OAuth2 client-credentials token exchange, lists organizations and a few devices, and — with a hostname argument — runs the same hostname search the device-resolution pipeline uses.

Honest limitations

  • The "Open in NinjaOne" deep link requires the engineer to already be logged into NinjaOne in their browser — it is a console URL, not a standalone remote-session launcher.
  • No remote-session launch, no reboot/script actions — this is a strictly read-only "glance" feature. Any action capability is a separate, not-yet-built tier.
  • Systray hints are client-reported, exactly like the browser user agent — useful for lookup, never trusted for identity/authorization.
  • Live telemetry values (disk, patches, AV, alerts) reflect NinjaOne's own last-check-in data for that device, not a real-time poll triggered by the chat.

See also


Did this page help you?