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 → MaveraPOST /personas (per segment) → POST /focus-groups (test EVPs) → Validated employer value props
Architecture
Code
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]}")
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)}`);
}
Example Output
{
"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
RSC export formats
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.Privacy and compliance
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.
Small export sizes
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.