Persona Detection API
The Persona Detection API allows you to detect user personas and intent independently of the ai12z bot. Use this approach when users are interacting with your website outside the bot or when you need persona detection

before the bot is opened.
When to Use This APIβ
Use the API approach when:
- π Pre-bot personalization - Detect persona before user opens the bot
- π₯οΈ Server-side personalization - Personalize content during page rendering
- π Custom workflows - Integrate persona detection into your own application logic
- π Analytics systems - Track user intent across your site
- ποΈ CMS integration - Magnolia, Drupal, or other CMS-driven personalization
- ποΈ E-commerce flows - Personalize product recommendations outside chat
Use the event-driven approach when:
- π¬ Users are actively chatting with the ai12z bot
- β‘ You want automatic, real-time persona detection based on bot queries
- π€ The bot handles all persona analysis automatically
π For event-driven persona detection, see Intent + Persona Personalizer
How It Worksβ
- User interacts with your website (clicks, searches, navigates)
- Your code collects signals (search queries, button clicks, page views)
- You call the API with collected queries and user context
- API returns persona with confidence score and suggested actions
- You personalize the page based on the detected persona
Unlike the event-driven approach where the bot automatically detects persona during conversations, this API gives you full control over when and how persona detection occurs.
API Endpointβ
POST https://api.ai12z.net/bot/intent_persona
Key Difference from Event-Driven Approach:
- Event-driven: Bot automatically sends queries to persona engine (no manual API calls needed)
- API approach: You manually collect user signals and call this endpoint when ready
Authenticationβ
Include your API key in the request body (not in headers):
{
"apiKey": "your-api-key-here"
}
Request Formatβ
This API uses the same personaCatalog structure as the event-driven approach, but you control when and how to call it.
Complete Request Exampleβ
Scenario: User searches your site for "car loans" without opening the bot. You want to personalize the page.
{
"apiKey": "f3e358c42bd122a85620e4b60489d196dd1786bd7211114c48613810454774df",
"queries": [
"do you offer car loans",
"what are the rates for auto financing"
],
"clicks": ["cta_view_rates", "link_auto_loans"],
"origin": "https://www.example.com/index.html",
"attributes": {
"personaEnable": true,
"personaCatalog": [
{
"id": "auto_buyer",
"label": "Auto Buyer",
"description": "For auto financingβget prequalified, explore vehicle financing options, and browse next steps.",
"panel": "auto",
"next": [
{ "type": "cta", "id": "get_prequalified" },
{ "type": "cta", "id": "view_auto_financing_options" },
{ "type": "heroImage", "id": "vehicle_marketplace_showcase" },
{ "type": "urlChange", "id": "https://example.com/auto-loans" }
]
},
{
"id": "homeowner_mortgage",
"label": "Homeowner",
"description": "For home buying or mortgage needsβget prequalified, estimate payments, and explore the journey.",
"panel": "mortgage",
"next": [
{ "type": "form", "id": "mortgage_prequalification" },
{ "type": "cta", "id": "calculate_mortgage_payment" },
{ "type": "heroImage", "id": "home_buying_journey" }
]
},
{
"id": "investor",
"label": "Investor",
"description": "For investing goalsβopen an account, explore portfolio options, or connect with an advisor.",
"panel": "investing",
"next": [
{ "type": "cta", "id": "open_investment_account" },
{ "type": "heroImage", "id": "investment_portfolio_showcase" },
{ "type": "cta", "id": "talk_to_financial_advisor" }
]
}
],
"initialPersonaId": "general",
"activePersonaId": "general",
"profile": {
"customerId": "123",
"segment": "banking",
"age": 35,
"lifestage": "family"
},
"context": {
"pageType": "banking",
"locale": "en-US",
"origin": "https://www.example.com/index.html"
}
}
}
Request Parametersβ
| Parameter | Type | Required | Description |
|---|---|---|---|
apiKey | string | Yes | Your ai12z API key |
queries | array | Yes | Array of recent user queries (1-5 recommended) |
clicks | array | No | Array of CTA/button IDs user clicked |
origin | string | No | Current page URL for context |
attributes | object | Yes | Configuration object (see below) |
Attributes Objectβ
| Property | Type | Required | Description |
|---|---|---|---|
personaEnable | boolean | Yes | Must be true to activate persona detection |
personaCatalog | array | Yes | Array of persona definitions |
initialPersonaId | string | No | Initial persona guess (from CDP/CMS) |
activePersonaId | string | No | Currently active persona |
profile | object | No | Customer profile data (CDP) |
context | object | No | Page/session metadata |
Response Formatβ
Success Responseβ
{
"requestId": "ip_7c2f1a",
"activePersonaId": "auto_buyer",
"confidence": 0.89,
"personaChanged": true,
"panel": "auto",
"next": [
{ "type": "cta", "id": "get_prequalified" },
{ "type": "cta", "id": "view_auto_financing_options" },
{ "type": "heroImage", "id": "vehicle_marketplace_showcase" },
{ "type": "urlChange", "id": "https://example.com/auto-loans" }
],
"thresholdApplied": false
}
Response Fieldsβ
| Field | Type | Description |
|---|---|---|
requestId | string | Unique identifier for this request |
activePersonaId | string | Detected persona ID |
confidence | number | Confidence score (0.0 to 1.0) |
personaChanged | boolean | Whether persona changed from activePersonaId in request |
panel | string | Bot panel to display (from persona catalog) |
next | array | Suggested actions based on persona |
thresholdApplied | boolean | True if confidence was below 0.74 threshold |
Low Confidence Responseβ
When confidence is below the threshold (0.74), the API returns the current active persona without changing it:
{
"requestId": "ip_8d3e2b",
"activePersonaId": "general",
"confidence": 0.62,
"personaChanged": false,
"thresholdApplied": true
}
Client-Side Integrationβ
Use this when you want to detect persona before users interact with the bot, or based on website navigation patterns.
Use Case: Search Box Persona Detectionβ
Detect persona as users search your website (not the bot):
// Track searches in your site's search box (not bot queries)
const searchBox = document.querySelector("#site-search")
let searchQueries = []
searchBox.addEventListener("submit", async (e) => {
e.preventDefault()
const query = e.target.querySelector("input").value
searchQueries.push(query)
if (searchQueries.length > 5) searchQueries.shift()
// Execute the search
performSearch(query)
// Detect persona after 2+ searches
if (searchQueries.length >= 2) {
await detectPersona(searchQueries)
}
})
Basic fetch API Implementationβ
async function detectPersona(queries, attributes) {
try {
const response = await fetch("https://api.ai12z.net/bot/intent_persona", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
apiKey: "your-api-key",
queries: queries,
origin: window.location.href,
attributes: attributes,
}),
})
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}
const result = await response.json()
console.log("Detected persona:", result)
// Handle the result
handlePersonaDetection(result)
return result
} catch (error) {
console.error("Persona detection failed:", error)
return null
}
}
function handlePersonaDetection(result) {
if (!result.personaChanged) {
console.log("Persona unchanged")
return
}
console.log(`Persona changed to: ${result.activePersonaId}`)
console.log(`Confidence: ${result.confidence}`)
console.log(`Panel: ${result.panel}`)
// Handle suggested actions
result.next?.forEach((action) => {
switch (action.type) {
case "urlChange":
// Navigate to new page
window.location.href = action.id
break
case "cta":
// Show CTA button
showCTA(action.id)
break
case "form":
// Display form
showForm(action.id)
break
case "heroImage":
// Swap hero image
updateHeroImage(action.id)
break
}
})
}
Complete Working Example: Site Search Integrationβ
This example shows persona detection based on site search (not bot chat):
<!doctype html>
<html>
<head>
<title>Banking Website with Search-Based Persona Detection</title>
</head>
<body>
<h1>Banking Services</h1>
<!-- Site search box (not bot) -->
<form id="site-search">
<input type="text" name="q" placeholder="Search our site..." required />
<button type="submit">Search</button>
</form>
<div id="persona-banner" style="display:none;">
<p>
Based on your interests, we think you might be looking for
<span id="persona-type"></span>
</p>
</div>
<div id="search-results"></div>
<script>
const API_KEY = "your-api-key"
const API_URL = "https://api.ai12z.net/bot/intent_persona"
let searchQueries = []
let detectedPersona = null
const personaCatalog = [
{
id: "auto_buyer",
label: "Auto Buyer",
description: "For auto financing options and vehicle loans.",
panel: "auto",
next: [
{ type: "urlChange", id: "/auto-loans" },
{ type: "cta", id: "get_prequalified" },
],
},
{
id: "homeowner_mortgage",
label: "Homeowner",
description: "For home buying and mortgage needs.",
panel: "mortgage",
next: [
{ type: "urlChange", id: "/mortgages" },
{ type: "form", id: "mortgage_calculator" },
],
},
]
// Handle site search submissions
document
.getElementById("site-search")
.addEventListener("submit", async (e) => {
e.preventDefault()
const query = e.target.q.value.trim()
if (!query) return
// Add to query history
searchQueries.push(query)
if (searchQueries.length > 5) searchQueries.shift()
// Show search results (your existing search logic)
displaySearchResults(query)
// Detect persona after 2+ searches
if (searchQueries.length >= 2) {
await detectPersona()
}
})
async function detectPersona() {
try {
const response = await fetch(API_URL, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
apiKey: API_KEY,
queries: searchQueries,
origin: window.location.href,
attributes: {
personaEnable: true,
personaCatalog: personaCatalog,
initialPersonaId: "general",
activePersonaId: detectedPersona || "general",
profile: { customerId: "123" },
context: { pageType: "search" },
},
}),
})
if (!response.ok) return
const result = await response.json()
handlePersonaResult(result)
} catch (error) {
console.error("Persona detection failed:", error)
}
}
function handlePersonaResult(result) {
if (!result.personaChanged) return
detectedPersona = result.activePersonaId
// Show persona banner
document.getElementById("persona-banner").style.display = "block"
document.getElementById("persona-type").textContent =
result.activePersonaId.replace("_", " ")
// Handle actions
result.next?.forEach((action) => {
if (action.type === "urlChange") {
// Optionally redirect to persona-specific page
console.log("Suggested redirect:", action.id)
// Uncomment to auto-redirect:
// setTimeout(() => window.location.href = action.id, 2000);
}
})
// Track for analytics
trackPersona(result.activePersonaId, result.confidence)
}
function displaySearchResults(query) {
// Your existing search results display logic
document.getElementById("search-results").innerHTML =
``
}
function trackPersona(personaId, confidence) {
console.log(`Persona: ${personaId}, Confidence: ${confidence}`)
// Add your analytics tracking here
}
</script>
</body>
</html>
Key Points:
- β Detects persona from site search, not bot chat
- β Collects 2+ queries before calling API
- β Optionally redirects to persona-specific pages
- β Works before user ever opens the bot
Server-Side Integrationβ
Use server-side detection for pre-rendering personalized content or SSR frameworks.
Node.js Exampleβ
const fetch = require("node-fetch")
async function detectPersona(queries, userProfile) {
const response = await fetch("https://api.ai12z.net/bot/intent_persona", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
apiKey: process.env.AI12Z_API_KEY,
queries: queries,
attributes: {
personaEnable: true,
personaCatalog: getPersonaCatalog(),
profile: userProfile,
context: {
pageType: "banking",
locale: "en-US",
},
},
}),
})
return await response.json()
}
// Use in route handler
app.post("/api/personalize", async (req, res) => {
const { queries, userId } = req.body
const userProfile = await getUserProfile(userId)
const persona = await detectPersona(queries, userProfile)
// Store in session/database
await saveUserPersona(userId, persona.activePersonaId)
res.json({
persona: persona.activePersonaId,
recommendations: getRecommendations(persona),
})
})
Python Exampleβ
import requests
import os
def detect_persona(queries, user_profile):
url = "https://api.ai12z.net/bot/intent_persona"
payload = {
"apiKey": os.getenv("AI12Z_API_KEY"),
"queries": queries,
"attributes": {
"personaEnable": True,
"personaCatalog": get_persona_catalog(),
"profile": user_profile,
"context": {
"pageType": "banking",
"locale": "en-US"
}
}
}
response = requests.post(url, json=payload)
response.raise_for_status()
return response.json()
# Usage example
result = detect_persona(
queries=["do you offer car loans", "what are auto loan rates"],
user_profile={"customerId": "123", "segment": "banking"}
)
print(f"Detected persona: {result['activePersonaId']}")
print(f"Confidence: {result['confidence']}")
Best Practicesβ
1. Query Collectionβ
- Collect 2-5 queries before calling the API for better accuracy
- Include recent queries only (last 5 minutes recommended)
- Clean and normalize queries before sending
2. Rate Limitingβ
- Implement cooldown periods (10-15 seconds minimum between calls)
- Don't call on every keystroke - wait for complete queries
- Cache results to avoid redundant calls
let lastCallTime = 0
const COOLDOWN = 12000 // 12 seconds
async function detectPersonaWithCooldown(queries, attributes) {
const now = Date.now()
if (now - lastCallTime < COOLDOWN) {
console.log("Cooldown active, skipping call")
return null
}
lastCallTime = now
return await detectPersona(queries, attributes)
}
3. Error Handlingβ
- Always implement try-catch for network errors
- Fallback to default persona on errors
- Log errors for monitoring
async function safeDetectPersona(queries, attributes) {
try {
const result = await detectPersona(queries, attributes)
return result
} catch (error) {
console.error("Persona detection failed:", error)
// Fallback to default
return {
activePersonaId: attributes.initialPersonaId || "general",
confidence: 0,
personaChanged: false,
}
}
}
4. Privacy & Securityβ
- Never send PII (Personally Identifiable Information) in queries
- Use customer IDs instead of names/emails in profile data
- Consider encrypting sensitive profile data
- Comply with GDPR/CCPA requirements
5. Performance Optimizationβ
- Call API server-side when possible for faster responses
- Cache persona results in session storage
- Use CDN for API endpoints (production)
- Implement request debouncing
Common Integration Patternsβ
Pattern 1: Progressive Enhancementβ
Start with a default experience, then enhance based on detected persona:
// Initial page load - default content
showDefaultContent()
// After user interaction - detect and personalize
userQueries.length >= 2 && detectPersona().then(applyPersonalization)
Pattern 2: Real-Time Adaptationβ
Continuously adapt as user explores:
let personaScore = {}
async function adaptivePersona(query) {
queryHistory.push(query)
if (queryHistory.length >= 2 && queryHistory.length % 2 === 0) {
const result = await detectPersona()
// Track persona consistency
personaScore[result.activePersonaId] =
(personaScore[result.activePersonaId] || 0) + result.confidence
// Only change if consistently detected
if (personaScore[result.activePersonaId] > 1.5) {
applyPersonalization(result)
}
}
}
Pattern 3: Server-Side Prerenderingβ
Detect persona server-side and pre-render personalized content:
// Express.js example
app.get("/landing/:persona?", async (req, res) => {
let persona = req.params.persona || "general"
// If no persona in URL, try to detect from query params
if (!req.params.persona && req.query.q) {
const result = await detectPersona([req.query.q], getUserProfile(req))
persona = result.activePersonaId
}
const content = await getPersonalizedContent(persona)
res.render("landing", { persona, content })
})
Troubleshootingβ
Issue: Low Confidence Scoresβ
Symptoms: API always returns confidence below 0.74
Solutions:
- Ensure
personaCatalogincludes clear, distinct descriptions - Collect more queries (3-5 recommended)
- Verify queries are substantive (not just "hi", "hello")
- Check that personas cover the expected user intents
Issue: Wrong Persona Detectedβ
Symptoms: API detects incorrect persona consistently
Solutions:
- Review persona descriptions for overlap/ambiguity
- Add more distinct keywords to descriptions
- Include
contextdata (page type, user segment) - Pass richer
profiledata from CDP
Issue: API Timeout/Errorsβ
Symptoms: Requests fail or timeout
Solutions:
- Check API key validity
- Verify network connectivity
- Implement retry logic with exponential backoff
- Reduce payload size (trim long queries)
Comparison: API vs Event-Driven Approachβ
| Feature | API Approach (this page) | Event-Driven (persona.md) |
|---|---|---|
| When to use | User interacts with website (not bot) | User chats with ai12z bot |
| Trigger | Manual API call when ready | Automatic on bot messages |
| Use cases | Search, navigation, pre-bot personalization | Real-time chat analysis |
| Implementation | You call /intent_persona endpoint | Listen to messageReceived event |
| Control | Full control over timing | Automatic by bot |
| Query source | Site search, clicks, navigation | Bot conversation queries |
| Best for | Pre-rendering, SSR, CMS personalization | In-chat personalization |
Example scenarios:
- Use API: User searches "auto loans" in your site search box β personalize page before they open bot
- Use Event-driven: User opens bot and asks "do you offer car loans?" β bot automatically detects persona
Both approaches use the same personaCatalog and return the same response structureβthe only difference is when and how detection occurs.
Related Documentationβ
- Event-Driven Persona Detection - Automatic detection during bot conversations
- AI-Driven URL Navigation - Implementing
urlChangeactions - Bot Configuration - Panel setup
Note: The Persona Detection API requires ai12z platform version 2.0 or higher and an active subscription with persona detection enabled. Choose the API approach when you need persona detection before or outside of bot interactions.