> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mavera.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Candidate Data → Talent Personas

> Create data-grounded talent personas from LinkedIn RSC exports and test employer value propositions with Mavera Focus Groups

## Scenario

Through LinkedIn's Recruiter System Connect (RSC) or manual CSV exports from LinkedIn Recruiter, you have rich candidate profile data — titles, skills, industries, seniority levels, locations. Instead of building talent personas from intuition, you feed real candidate data into Mavera to create data-grounded personas, then test your employer value propositions against them.

**Flow:** LinkedIn RSC export (CSV/JSON) → Parse profiles → Mavera `POST /personas` (per segment) → `POST /focus-groups` (test EVPs) → Validated employer value props

### Architecture

```mermaid theme={"dark"}
flowchart LR
    A["LinkedIn Recruiter Export (CSV/JSON)"] --> B["Parse title, skills, industry, seniority"]
    B --> C["Segment by seniority × function"]
    C --> D["POST /api/v1/personas"]
    D --> E["POST /api/v1/focus-groups"]
    E --> F["Segment-specific EVP validation"]
```

## Code

<CodeGroup>
  ```python Python theme={"dark"}
  import os, json, csv, requests, time
  from collections import defaultdict

  MV = os.environ["MAVERA_API_KEY"]
  MV_BASE = "https://app.mavera.io/api/v1"
  MV_H = {"Authorization": f"Bearer {MV}", "Content-Type": "application/json"}

  # 1. Load exported LinkedIn candidate data
  # In production, this comes from RSC integration or Recruiter CSV export
  SAMPLE_CANDIDATES = [
      {"title": "Staff Engineer", "skills": ["Python", "Kubernetes", "System Design"], "industry": "Technology", "seniority": "Senior", "location": "SF Bay Area"},
      {"title": "Engineering Manager", "skills": ["Team Leadership", "Agile", "Java"], "industry": "Technology", "seniority": "Manager", "location": "NYC"},
      {"title": "Senior Data Scientist", "skills": ["ML", "Python", "Statistics"], "industry": "Finance", "seniority": "Senior", "location": "Chicago"},
      {"title": "VP Engineering", "skills": ["Strategy", "Team Building", "Architecture"], "industry": "SaaS", "seniority": "Executive", "location": "Remote"},
      {"title": "Backend Developer", "skills": ["Node.js", "PostgreSQL", "AWS"], "industry": "E-commerce", "seniority": "Mid", "location": "Austin"},
      {"title": "ML Engineer", "skills": ["PyTorch", "MLOps", "Python"], "industry": "AI/ML", "seniority": "Senior", "location": "Seattle"},
      {"title": "Platform Engineer", "skills": ["Terraform", "Kubernetes", "Go"], "industry": "Fintech", "seniority": "Senior", "location": "London"},
  ]

  # For CSV files from LinkedIn Recruiter export:
  # with open("linkedin_export.csv") as f:
  #     reader = csv.DictReader(f)
  #     SAMPLE_CANDIDATES = [
  #         {"title": row["Current Title"], "skills": row.get("Skills","").split(","),
  #          "industry": row.get("Industry",""), "seniority": row.get("Seniority","")}
  #         for row in reader
  #     ]

  # 2. Segment by seniority
  segments = defaultdict(list)
  for c in SAMPLE_CANDIDATES:
      segments[c["seniority"]].append(c)

  # 3. Create personas per segment
  persona_ids = []
  for seniority, candidates in segments.items():
      if not candidates:
          continue
      titles = list({c["title"] for c in candidates})[:5]
      all_skills = [s for c in candidates for s in c.get("skills", [])]
      top_skills = sorted(set(all_skills), key=all_skills.count, reverse=True)[:5]
      industries = list({c["industry"] for c in candidates})[:3]
      locations = list({c.get("location", "N/A") for c in candidates})[:3]

      p = requests.post(f"{MV_BASE}/personas", headers=MV_H, json={
          "name": f"LI Talent: {seniority}",
          "description": (
              f"{seniority}-level talent. N={len(candidates)}. "
              f"Titles: {', '.join(titles)}. Skills: {', '.join(top_skills)}. "
              f"Industries: {', '.join(industries)}. Locations: {', '.join(locations)}."
          ),
          "demographic": {
              "job_titles": titles,
              "industries": industries,
              "locations": locations,
          },
          "psychographic": {
              "seniority": seniority,
              "skills": top_skills,
              "career_stage": seniority.lower(),
          },
      }).json()
      persona_ids.append({"id": p["id"], "seniority": seniority, "n": len(candidates)})
      print(f"Persona: {p['id']} — {seniority} ({len(candidates)} profiles)")
      time.sleep(0.3)

  # 4. Test employer value propositions
  EVPS = {
      "mission": "We're on a mission to make AI accessible to every business, not just tech giants.",
      "growth": "Engineers here get promoted 2x faster than industry average. We invest in your career.",
      "tech": "Our stack is modern (Go, K8s, Postgres) and you'll ship to production on day one.",
      "culture": "Async-first, no meeting Wednesdays, unlimited PTO that people actually take (avg 28 days).",
  }

  evp_block = "\n".join(f"- **{k.title()}**: {v}" for k, v in EVPS.items())

  fg = requests.post(f"{MV_BASE}/focus-groups", headers=MV_H, json={
      "name": "Employer Value Proposition Test",
      "persona_ids": [p["id"] for p in persona_ids],
      "questions": [
          {"type": "ranking", "text": f"Rank these EVPs by how compelling they are to YOU:\n{evp_block}"},
          "Which EVP would make you respond to a recruiter's InMail?",
          "Which EVP feels like empty marketing? Why?",
          "What's missing from these value props that you'd need to hear?",
          "Write a one-line EVP that would make YOU apply.",
      ],
      "context": f"Company: Series B AI startup, 120 employees, $40M raised.\n\nValue Propositions:\n{evp_block}",
      "responses_per_persona": 3,
  }).json()

  for _ in range(20):
      time.sleep(5)
      data = requests.get(f"{MV_BASE}/focus-groups/{fg['id']}", headers=MV_H).json()
      if data.get("status") == "completed":
          break

  for resp in data.get("responses", []):
      seniority = next((p["seniority"] for p in persona_ids if p["id"] == resp.get("persona_id")), "?")
      print(f"\n[{seniority}] {resp.get('question','')[:60]}")
      print(f"  → {resp.get('answer','')[:300]}")
  ```

  ```javascript JavaScript theme={"dark"}
  const MV = process.env.MAVERA_API_KEY;
  const MV_BASE = "https://app.mavera.io/api/v1";
  const MV_H = { Authorization: `Bearer ${MV}`, "Content-Type": "application/json" };

  // 1. Candidate data (from RSC export or CSV)
  const candidates = [
    { title: "Staff Engineer", skills: ["Python", "Kubernetes"], industry: "Technology", seniority: "Senior", location: "SF" },
    { title: "Engineering Manager", skills: ["Leadership", "Agile"], industry: "Technology", seniority: "Manager", location: "NYC" },
    { title: "Senior Data Scientist", skills: ["ML", "Python"], industry: "Finance", seniority: "Senior", location: "Chicago" },
    { title: "VP Engineering", skills: ["Strategy", "Architecture"], industry: "SaaS", seniority: "Executive", location: "Remote" },
    { title: "Backend Developer", skills: ["Node.js", "AWS"], industry: "E-commerce", seniority: "Mid", location: "Austin" },
    { title: "ML Engineer", skills: ["PyTorch", "MLOps"], industry: "AI/ML", seniority: "Senior", location: "Seattle" },
    { title: "Platform Engineer", skills: ["Terraform", "Go"], industry: "Fintech", seniority: "Senior", location: "London" },
  ];

  // 2. Segment
  const segments = {};
  for (const c of candidates) {
    (segments[c.seniority] ??= []).push(c);
  }

  // 3. Personas
  const personaIds = [];
  for (const [seniority, members] of Object.entries(segments)) {
    const titles = [...new Set(members.map((m) => m.title))].slice(0, 5);
    const allSkills = members.flatMap((m) => m.skills);
    const topSkills = [...new Set(allSkills)].sort(
      (a, b) => allSkills.filter((s) => s === b).length - allSkills.filter((s) => s === a).length
    ).slice(0, 5);

    const p = await fetch(`${MV_BASE}/personas`, {
      method: "POST", headers: MV_H,
      body: JSON.stringify({
        name: `LI Talent: ${seniority}`,
        description: `${seniority}-level. N=${members.length}. Titles: ${titles.join(", ")}. Skills: ${topSkills.join(", ")}.`,
        demographic: { job_titles: titles },
        psychographic: { seniority, skills: topSkills },
      }),
    }).then((r) => r.json());
    personaIds.push({ id: p.id, seniority, n: members.length });
    await new Promise((r) => setTimeout(r, 300));
  }

  // 4. EVP test
  const EVPS = {
    mission: "Make AI accessible to every business.",
    growth: "Engineers get promoted 2x faster than industry avg.",
    tech: "Modern stack (Go, K8s, Postgres). Ship on day one.",
    culture: "Async-first, no meeting Wednesdays, 28 avg PTO days.",
  };
  const evpBlock = Object.entries(EVPS).map(([k, v]) => `- ${k}: ${v}`).join("\n");

  const fg = await fetch(`${MV_BASE}/focus-groups`, {
    method: "POST", headers: MV_H,
    body: JSON.stringify({
      name: "EVP Test",
      persona_ids: personaIds.map((p) => p.id),
      questions: [
        { type: "ranking", text: `Rank EVPs:\n${evpBlock}` },
        "Which EVP would make you respond to an InMail?",
        "Which feels like empty marketing? Why?",
        "What's missing?",
        "Write a one-line EVP for YOU.",
      ],
      context: `Series B AI startup, 120 emp, $40M raised.\n\n${evpBlock}`,
      responses_per_persona: 3,
    }),
  }).then((r) => r.json());

  let data;
  for (let i = 0; i < 20; i++) {
    await new Promise((r) => setTimeout(r, 5000));
    data = await fetch(`${MV_BASE}/focus-groups/${fg.id}`, { headers: MV_H }).then((r) => r.json());
    if (data.status === "completed") break;
  }

  for (const resp of data.responses || []) {
    const seniority = personaIds.find((p) => p.id === resp.persona_id)?.seniority || "?";
    console.log(`\n[${seniority}] ${(resp.question || "").slice(0, 60)}`);
    console.log(`  → ${(resp.answer || "").slice(0, 300)}`);
  }
  ```
</CodeGroup>

### Example Output

```json theme={"dark"}
{
  "evp_rankings_by_seniority": {
    "Senior": ["tech", "culture", "growth", "mission"],
    "Manager": ["growth", "culture", "mission", "tech"],
    "Executive": ["mission", "growth", "culture", "tech"],
    "Mid": ["growth", "tech", "culture", "mission"]
  },
  "key_findings": [
    {
      "seniority": "Senior",
      "insight": "Tech stack is #1. 'Go + K8s + Postgres is the exact stack I want to work in. Ship on day one — prove it with a GitHub repo.'"
    },
    {
      "seniority": "Executive",
      "insight": "Mission is #1 but needs proof. 'Every AI company says this. Show me 3 non-tech customers using your product.'"
    },
    {
      "seniority": "Mid",
      "insight": "Growth is #1. '2x faster promotions — how? Show me the rubric and the data. Otherwise it's just a recruiting line.'"
    }
  ],
  "custom_evps": [
    { "seniority": "Senior", "evp": "We need someone to redesign our payment pipeline from 800ms to 200ms. Interested?" },
    { "seniority": "Executive", "evp": "120 engineers, $40M raised, and the exec team still writes code on Fridays. Join us." }
  ]
}
```

### Error Handling

<AccordionGroup>
  <Accordion title="RSC export formats">LinkedIn Recruiter exports come as CSV or XLSX. Parse with `csv` (Python) or `csv-parse` (Node). Column names vary by export version — map them dynamically.</Accordion>
  <Accordion title="Privacy and compliance">Never store or send candidate PII (names, emails, profile URLs) to Mavera. Aggregate to title/skill/industry level only. Comply with LinkedIn's Terms of Service.</Accordion>
  <Accordion title="Small export sizes">LinkedIn Recruiter exports may be capped at 1,000-2,500 profiles. For larger datasets, use RSC integration for programmatic access or run multiple exports by search criteria.</Accordion>
</AccordionGroup>
