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.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:| Data | Why it matters |
|---|---|
| Billing plan & status | ”Can I use feature X?” depends on their plan |
| Forms created | Helps answer “How do I edit my form?” or “Where are my forms?” |
| Form submissions received | Indicates onboarding progress, troubleshooting submission issues |
| Scheduling pages & meetings | Context for scheduling-related questions |
| Connected integrations | ”Why isn’t my HubSpot sync working?” requires knowing connection status |
| AI credit usage | ”How many AI credits do I have left?” |
| Onboarding milestones | Determines if the user is new vs. experienced |
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:| Mechanism | Best for | Example |
|---|---|---|
User traits (identify) | Simple attributes about the person | name, email, role, plan |
Company traits (identifyCompany) | Simple attributes about the organization | company name, plan, industry |
Context entries (setContext) | Rich, structured data the AI should reference | integration statuses, metrics, feature flags |
User-Scoped vs. Company-Scoped
Data can be scoped to the individual user or to their company/team:| Scope | When to use | Examples |
|---|---|---|
| User-scoped | Data specific to one person | Has this user created a form? Has this user connected an integration? |
| Company-scoped | Data shared across the team | Total forms across the team, billing plan, connected integrations |
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: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.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.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: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:| Event | What to update |
|---|---|
| User or team created at signup | User + company traits via /api/sdk/users/identify and /api/sdk/companies/identify (required when signup and first widget load are separate) |
| Integration connected/disconnected | Integration context |
| Plan upgraded/downgraded | Billing traits & context |
| Key milestones (first form created, etc.) | User activity context |
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.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.Step 7: Review Your Implementation Checklist
Before shipping, verify you’ve covered each area: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.Company traits are set on login
identifyCompany() is called with company name, plan, and billing details.Context entries cover key product areas
At minimum: product usage metrics, integration statuses, and billing/usage data.
Dashboard load sends fresh data
Every time the user opens the app, the latest data is sent via the script.
Critical events trigger server-side syncs
Integration changes, plan changes, and key milestones push updates via the REST API.
A periodic job refreshes aggregate data
A weekly (or daily) background job updates counts and usage metrics.
Putting It All Together
Here’s a complete example for a forms & scheduling SaaS app, showing how all the pieces connect:- “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
Use count queries instead of fetching rows
Use count queries instead of fetching rows
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.
Run all queries in parallel
Run all queries in parallel
Use
Promise.all() (or your language’s equivalent) to run independent database queries simultaneously. This turns 7 sequential queries into 1 parallel batch.Make server-side syncs fire-and-forget
Make server-side syncs fire-and-forget
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.Batch backfills with rate limiting
Batch backfills with rate limiting
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.
Fetch only the fields you need
Fetch only the fields you need
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.