Skip to main content

Overview

The most effective HaloAgents integrations go beyond basic user identity. When the AI agent has deep context about a user’s product usage, billing status, and current issues, it can resolve support questions instantly instead of asking clarifying questions. This guide walks you through the thinking process of planning what data to send, how to structure it, and how to keep it up to date — including for users who already exist in your system.
Before reading this guide, make sure you’re familiar with the Data Model and the difference between traits and context.

Step 1: Map Out Your Product Data

Start by listing the key data in your app that would help an AI support agent answer questions. Think about what a human support agent would look up before responding to a ticket. For a forms & scheduling SaaS product, the list might look like:
You don’t need to send every piece of data in your database. Focus on data the AI would need to answer the most common support questions.

Step 2: Decide What Goes Where

HaloAgents has three data mechanisms, each with a different purpose: The rule of thumb: if it’s a single value (string, number, boolean), it’s probably a trait. If it’s structured data (lists, nested objects, multiple related values), it’s context.

User-Scoped vs. Company-Scoped

Data can be scoped to the individual user or to their company/team: Most product data is company-scoped (plans, integrations, aggregate counts). User-scoped data is typically about the individual’s activity or onboarding progress.

Step 3: Design Your Traits

User Traits

Start with the recommended fields (name, email, role), then add product-specific traits that describe the user’s state:
Notice the has_* boolean fields — these are onboarding milestones. The AI can use them to determine if the user is new (“I see you haven’t created a form yet — let me walk you through it”) vs. experienced.

Company Traits

Start with recommended fields (name, plan, industry), then add billing and plan-level data:

Step 4: Design Your Context Entries

Context entries give the AI structured data it can reference in detail. Plan context entries around the types of questions users ask.

Onboarding & Activity (Status)

Track what the user has and hasn’t done. This helps the AI provide guidance appropriate to their experience level.
Now when a user asks “How do I get started?”, the AI knows they’ve already created a form and received submissions, so it can skip those steps and suggest booking a meeting or exploring integrations.

Product Metrics (Metric)

Aggregate usage data helps the AI answer “how much” and “how many” questions.

Integration Status (Integration)

If your product has integrations, send their connection states. This is one of the highest-value context types — a huge portion of support questions are about integrations.
When a user asks “Why isn’t my Zapier integration working?”, the AI immediately knows Zapier isn’t connected and can guide them through setup — no back-and-forth needed.

Billing & Usage (Metric)

Billing context helps the AI answer plan and pricing questions without escalation.

Step 5: Plan Your Data Sources

Now that you know what to send, decide where the data comes from in your app.

Parallel Queries for Performance

Fetch all your data in parallel. If you’re using a database, most of these can be lightweight count queries:
Use count-only queries wherever possible. You don’t need to fetch full rows to get aggregate numbers — just the counts.

Where to Run the Queries

The best place is typically your app’s authenticated layout or dashboard shell — the component that wraps every authenticated page. This ensures:
  • Data is fetched once per session (not on every page navigation)
  • The user is already authenticated, so you have their ID and team ID
  • The data is available before the user opens the chat widget

Step 6: Plan Your Context Refresh Strategy

Data goes stale. A user might connect an integration, receive a new submission, or change their plan — and the AI should know about it. Plan multiple layers to keep context fresh.

Layer 1: On Dashboard Load (Client-Side Script)

This is your primary mechanism. Every time the user loads your app, HaloAgents sends fresh data. This covers all users, including existing users who were active before you integrated HaloAgents. The first time they log in after your deployment, all their historical data (form counts, integrations, billing) is fetched and sent.

Layer 2: Event-Driven Updates (Server-Side REST API)

For critical state changes that happen between page loads, update HaloAgents immediately using the REST API. Common triggers: Use a shared helper function to avoid duplicating logic:
Call this helper from your event handlers as fire-and-forget (wrapped in try/catch so it never breaks the main flow):

Layer 3: Periodic Background Sync

For aggregate data that changes gradually (submission counts, meeting counts, credit usage), schedule a periodic background job. Weekly is usually sufficient.
This catches any changes that happened outside of the event-driven updates and ensures data stays fresh even if a user hasn’t logged in recently.

Layer 4: One-Time Backfill for Existing Users

When you first integrate HaloAgents, your existing users already have data (forms, submissions, integrations) that the AI should know about. Run a one-time backfill to populate HaloAgents with historical data for all existing users and companies.
Reuse the same syncCompanyContext() helper for the backfill, periodic sync, and event-driven updates. This ensures every team gets the same data structure regardless of how the sync is triggered.

Step 7: Review Your Implementation Checklist

Before shipping, verify you’ve covered each area:
1

User traits are set on login and at signup

identify() is called with name, email, role, and product-specific fields on every authenticated load. If signup and first login can be separate, the signup API also calls /api/sdk/users/identify with signed_up_at from your product database.
2

Company traits are set on login

identifyCompany() is called with company name, plan, and billing details.
3

Context entries cover key product areas

At minimum: product usage metrics, integration statuses, and billing/usage data.
4

Dashboard load sends fresh data

Every time the user opens the app, the latest data is sent via the script.
5

Critical events trigger server-side syncs

Integration changes, plan changes, and key milestones push updates via the REST API.
6

A periodic job refreshes aggregate data

A weekly (or daily) background job updates counts and usage metrics.
7

Existing users are backfilled

A one-time script populates HaloAgents with historical data for all existing users.

Putting It All Together

Here’s a complete example for a forms & scheduling SaaS app, showing how all the pieces connect:
With this setup, the AI can handle questions like:
  • “How many submissions have I received?” — 1,847 total across 12 forms.
  • “Why isn’t HubSpot syncing?” — It sees the error status and can guide troubleshooting.
  • “Can I use the AI features?” — It knows the plan and remaining credits.
  • “How do I get started?” — It knows the user has already created forms but hasn’t booked a meeting, so it suggests that next.
  • “What plan am I on?” — Business plan, annual billing, active status.

Performance Tips

When you only need totals (form count, submission count), use your database’s count mechanism instead of fetching and counting rows. This is significantly faster and transfers less data.
Use Promise.all() (or your language’s equivalent) to run independent database queries simultaneously. This turns 7 sequential queries into 1 parallel batch.
When calling the REST API from event handlers (OAuth callbacks, webhooks), wrap the call in try/catch and don’t await it in the critical path. A failed sync should never break your user’s flow.
When backfilling all existing teams, add delays between API calls or use a job queue with concurrency limits to avoid overwhelming your database or the HaloAgents API.
For integration queries, select only the columns you need (type, is_active, last_error) instead of full rows. For billing, a single-row lookup is sufficient.