Digital Twin Survey
This guide walks you through running an audience survey using digital twins — from authentication to interpreting group opinions.
Digital twins are AI personas grounded in real demographic data. You can ask them questions individually or as a group, and get responses that reflect their demographic profile, values, and perspectives.
What you'll build
By the end of this guide, you will:
- Authenticate with the neuroflash API
- Fetch your workspace
- Browse available demographic groups
- List twins in a group
- Ask a single twin a question
- Get group opinions from multiple twins
Prerequisites
- A neuroflash account with API access
- Your
client_idandclient_secret(see Authentication)
Step 1: Authenticate
First, obtain an access token:
- cURL
- Python
- Node.js
- Go
curl -X POST https://id.neuroflash.com/oauth/v2/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET" \
-d "scope=openid"
import requests
BASE_URL = "https://app.neuroflash.com/api"
# Authenticate
auth_response = requests.post(
"https://id.neuroflash.com/oauth/v2/token",
data={
"grant_type": "client_credentials",
"client_id": "YOUR_CLIENT_ID",
"client_secret": "YOUR_CLIENT_SECRET",
"scope": "openid",
},
)
token = auth_response.json()["access_token"]
headers = {"Authorization": f"Bearer {token}"}
const BASE_URL = "https://app.neuroflash.com/api";
// Authenticate
const authResponse = await fetch("https://id.neuroflash.com/oauth/v2/token", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
grant_type: "client_credentials",
client_id: "YOUR_CLIENT_ID",
client_secret: "YOUR_CLIENT_SECRET",
scope: "openid",
}),
});
const { access_token } = await authResponse.json();
const headers = { Authorization: `Bearer ${access_token}` };
package main
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"
)
const baseURL = "https://app.neuroflash.com/api"
func main() {
// Authenticate
data := url.Values{
"grant_type": {"client_credentials"},
"client_id": {"YOUR_CLIENT_ID"},
"client_secret": {"YOUR_CLIENT_SECRET"},
"scope": {"openid"},
}
resp, _ := http.Post(
"https://id.neuroflash.com/oauth/v2/token",
"application/x-www-form-urlencoded",
strings.NewReader(data.Encode()),
)
defer resp.Body.Close()
var authResult struct {
AccessToken string `json:"access_token"`
}
json.NewDecoder(resp.Body).Decode(&authResult)
token := authResult.AccessToken
}
Step 2: Get Your Workspace
Fetch your available workspaces and select the first one. The workspace ID is required for most API calls:
- cURL
- Python
- Node.js
- Go
curl "https://app.neuroflash.com/api/workspace-service/v1/workspaces" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
workspaces = requests.get(
f"{BASE_URL}/workspace-service/v1/workspaces",
headers=headers,
).json()
workspace_id = workspaces["_embedded"]["workspaces"][0]["id"]
print(f"Using workspace: {workspace_id}")
const workspaces = await fetch(
`${BASE_URL}/workspace-service/v1/workspaces`,
{ headers }
).then((r) => r.json());
const workspaceId = workspaces._embedded.workspaces[0].id;
console.log(`Using workspace: ${workspaceId}`);
req, _ := http.NewRequest("GET", baseURL+"/workspace-service/v1/workspaces", nil)
req.Header.Set("Authorization", "Bearer "+token)
wsResp, _ := http.DefaultClient.Do(req)
defer wsResp.Body.Close()
var wsResult struct {
Embedded struct {
Workspaces []struct {
ID string `json:"id"`
} `json:"workspaces"`
} `json:"_embedded"`
}
json.NewDecoder(wsResp.Body).Decode(&wsResult)
workspaceID := wsResult.Embedded.Workspaces[0].ID
fmt.Printf("Using workspace: %s\n", workspaceID)
Step 3: Browse Static Groups
neuroflash provides pre-built demographic groups with ready-to-use digital twins. List the available groups:
- cURL
- Python
- Node.js
- Go
curl "https://app.neuroflash.com/api/digital-twin-service/v1/static-groups" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
groups = requests.get(
f"{BASE_URL}/digital-twin-service/v1/static-groups",
headers=headers,
).json()
for group in groups:
print(f"{group['key']}: {group['label']} — {group['description']}")
const groups = await fetch(
`${BASE_URL}/digital-twin-service/v1/static-groups`,
{ headers }
).then((r) => r.json());
groups.forEach((g) => console.log(`${g.key}: ${g.label} — ${g.description}`));
req, _ := http.NewRequest("GET", baseURL+"/digital-twin-service/v1/static-groups", nil)
req.Header.Set("Authorization", "Bearer "+token)
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
var groups []struct {
Key string `json:"key"`
Label string `json:"label"`
Description string `json:"description"`
}
json.NewDecoder(resp.Body).Decode(&groups)
for _, g := range groups {
fmt.Printf("%s: %s — %s\n", g.Key, g.Label, g.Description)
}
Response:
[
{
"key": "gen_z",
"label": "Gen Z",
"description": "Generation Z (born 1997-2012)"
},
{
"key": "millennials",
"label": "Millennials",
"description": "Millennials (born 1981-1996)"
},
{
"key": "gen_x",
"label": "Generation X",
"description": "Generation X (born 1965-1980)"
},
{
"key": "baby_boomers",
"label": "Baby Boomers",
"description": "Baby Boomers (born 1946-1964)"
},
{
"key": "gen_alpha",
"label": "Generation Alpha",
"description": "Generation Alpha (born 2010+)"
}
]
Step 4: List Twins in a Group
Pick the first group and get the individual digital twins within it:
- cURL
- Python
- Node.js
- Go
curl "https://app.neuroflash.com/api/digital-twin-service/v1/workspaces/{workspace_id}/static-groups/gen_z/twins?page=1&size=5" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
group_key = groups[0]["key"]
twins = requests.get(
f"{BASE_URL}/digital-twin-service/v1/workspaces/{workspace_id}/static-groups/{group_key}/twins",
headers=headers,
params={"page": 1, "size": 5},
).json()
for twin in twins["data"]:
print(f"{twin['name']} — {twin['title']} (Age: {twin['age']}, {twin['location']})")
const groupKey = groups[0].key;
const twins = await fetch(
`${BASE_URL}/digital-twin-service/v1/workspaces/${workspaceId}/static-groups/${groupKey}/twins?page=1&size=5`,
{ headers }
).then((r) => r.json());
twins.data.forEach((t) =>
console.log(`${t.name} — ${t.title} (Age: ${t.age}, ${t.location})`)
);
groupKey := groups[0].Key
twinsURL := fmt.Sprintf("%s/digital-twin-service/v1/workspaces/%s/static-groups/%s/twins?page=1&size=5",
baseURL, workspaceID, groupKey)
req, _ := http.NewRequest("GET", twinsURL, nil)
req.Header.Set("Authorization", "Bearer "+token)
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
var twinsResult struct {
Data []struct {
ID string `json:"id"`
Name string `json:"name"`
Title string `json:"title"`
Age int `json:"age"`
Location string `json:"location"`
} `json:"data"`
}
json.NewDecoder(resp.Body).Decode(&twinsResult)
for _, t := range twinsResult.Data {
fmt.Printf("%s — %s (Age: %d, %s)\n", t.Name, t.Title, t.Age, t.Location)
}
Response:
{
"data": [
{
"id": "a1b2c3d4-...",
"name": "Jens Bauer",
"title": "Tech-Savvy Millennial",
"age": 34,
"gender": "male",
"location": "Munich",
"jobTitle": "Software Engineer",
"staticGroupKey": "millennials",
"_links": {
"avatarUrl": "https://storage.googleapis.com/..."
}
}
],
"page": {
"size": 5,
"totalElements": 20,
"totalPages": 4,
"currentPage": 1
}
}
Step 5: Ask a Single Twin
Now ask an individual twin a question. The twin responds in character, based on its demographic profile:
- cURL
- Python
- Node.js
- Go
curl -X POST "https://app.neuroflash.com/api/digital-twin-service/v1/workspaces/{workspace_id}/twins/{twin_id}/chat-completions" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"messages": [
{
"role": "user",
"content": "What do you think about electric vehicles? Would you buy one?"
}
]
}'
twin_id = twins["data"][0]["id"]
response = requests.post(
f"{BASE_URL}/digital-twin-service/v1/workspaces/{workspace_id}/twins/{twin_id}/chat-completions",
headers=headers,
json={
"messages": [
{
"role": "user",
"content": "What do you think about electric vehicles? Would you buy one?",
}
]
},
).json()
print(f"Answer: {response['answer']}")
print(f"Reason: {response['reason']}")
const twinId = twins.data[0].id;
const response = await fetch(
`${BASE_URL}/digital-twin-service/v1/workspaces/${workspaceId}/twins/${twinId}/chat-completions`,
{
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify({
messages: [
{
role: "user",
content:
"What do you think about electric vehicles? Would you buy one?",
},
],
}),
}
).then((r) => r.json());
console.log(`Answer: ${response.answer}`);
console.log(`Reason: ${response.reason}`);
twinID := twinsResult.Data[0].ID
chatURL := fmt.Sprintf("%s/digital-twin-service/v1/workspaces/%s/twins/%s/chat-completions",
baseURL, workspaceID, twinID)
body, _ := json.Marshal(map[string]any{
"messages": []map[string]string{
{"role": "user", "content": "What do you think about electric vehicles? Would you buy one?"},
},
})
req, _ := http.NewRequest("POST", chatURL, bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
var chatResult struct {
Answer string `json:"answer"`
Reason string `json:"reason"`
}
json.NewDecoder(resp.Body).Decode(&chatResult)
fmt.Printf("Answer: %s\n", chatResult.Answer)
fmt.Printf("Reason: %s\n", chatResult.Reason)
Response:
{
"answer": "I'm definitely considering it for my next car. The tech has gotten really good, and with charging infrastructure improving in Munich, it makes sense both financially and environmentally.",
"reason": "As a tech-savvy millennial software engineer, Jens is drawn to innovative technology and is environmentally conscious. His urban Munich location provides good charging infrastructure, making EVs practical."
}
By default, useVerbalizedSampling is true. This means the twin generates 5 probability-weighted candidate responses and selects the most representative one, producing more consistent and reliable answers.
Next Steps
- Learn about group chat conversations for multi-turn discussions
- Explore the Digital Twins API reference for all endpoints
- See Audiences to create custom target audiences