LinkedIn Graph Analysis — Capability Audit¶
Date: 2026-03-02
Prepared by: Claude (Opus 4.6)
Capability Slug: linkedin_graph_analysis
Handler: LinkedInGraphCapability.php
Part 1: Current State Assessment¶
What Exists¶
The LinkedIn Graph Analysis capability is registered in the CapabilityRegistry as an analysis-category capability with 5 analysis types:
| Analysis Type | Credits | Status |
|---|---|---|
| Post Performance | 5 | Prompt-only (no live data) |
| Audience Insights | 10 | Prompt-only (no live data) |
| Relationship Graph | 15 | Prompt-only (no live data) |
| ICP Alignment | 10 | Prompt-only (no live data) |
| Content-to-Marketplace Correlation | 15 | Prompt-only (no live data) |
The Critical Gap¶
The capability does not fetch LinkedIn data. Line 87-88 of LinkedInGraphCapability.php:
Every analysis method sends whatever $parameters['data'] the user provides (or nothing) to Claude 3 Sonnet via Bedrock and asks it to analyze. Without actual LinkedIn API data flowing in, this is an AI prompt wrapper — not a pipeline intelligence tool.
LinkedIn OAuth — What's Actually Configured¶
Current scopes (from config/social-media.php):
These are publishing scopes. They allow: - Authenticating a user (openid, profile, email) - Posting to the user's LinkedIn feed (w_member_social)
What's NOT configured (required for graph analysis):
| Scope / API Product | What It Unlocks | Required For |
|---|---|---|
r_organization_social |
Read org posts & engagement | Post Performance |
r_organization_followers |
Follower demographics | Audience Insights |
r_1st_connections_size |
Connection count | Relationship Graph |
| Marketing Developer Platform | Campaign analytics, audience insights | All analysis types |
| Community Management API | Comment management, mentions | Engagement tracking |
| Advertising API | Audience demographics at scale | ICP Alignment |
LinkedIn Developer Access Status: INCOMPLETE
The Linkedin.php helper has a getPostAnalytics() method that calls rest/socialMetadata/{urn} — this returns basic engagement counts (likes, shares, comments) for posts the user published. It does NOT provide:
- Audience demographics (title, company, industry of engagers)
- Follower analytics
- Connection/relationship data
- Content attribution to external conversions
What the Existing Helper CAN Do¶
| Method | Endpoint | What It Returns |
|---|---|---|
publishText() |
rest/posts |
Post creation |
publishImage() |
rest/images + rest/posts |
Image + post creation |
publishVideo() |
rest/videos + rest/posts |
Video upload + post creation |
getPostAnalytics() |
rest/socialMetadata/{urn} |
Basic engagement counts |
getAccountInfo() |
v2/userinfo |
Profile name, email, picture |
Missing methods for graph analysis:
- getFollowerDemographics() — requires Organization API
- getEngagerProfiles() — requires Marketing Developer Platform
- getConnectionGraph() — not available via API (LinkedIn restricts this)
- getPostImpressionDemographics() — requires Advertising API
Part 2: Architecture Questions¶
Does the graph become input into an agent?¶
Current state: No. The capability is a terminal output — it produces analysis text and returns it as execution step results. The output does not persist as a data source that other capabilities can consume.
How it works today:
Agent Execution → LinkedInGraphCapability::execute() → Claude prompt → JSON analysis → step_results (stored in AgentExecution)
The step_results JSON is stored in ext_content_manager_agent_executions.step_results but is not indexed, queryable, or referenceable by subsequent capability executions.
Does it sit alongside KB and Brand Voice?¶
Current integration is one-directional:
- Brand Voice → flows into → LinkedIn Graph Analysis (via buildAnalysisPrompt())
- Knowledge Base → not connected → LinkedIn Graph Analysis
- LinkedIn Graph Analysis → does not flow back into → anything
Brand voice context (company name, industry, target audience, ICP) is injected into every analysis prompt. But the analysis output does not enrich the brand voice, KB, or any persistent data store.
Should it go with Brand Voice? Become a brand sentiment input?¶
This is the most strategically interesting question. Consider three architectural options:
Option A: LinkedIn Graph as Agent Capability (Current)¶
Strengths: Simple, low maintenance, no LinkedIn API dependency Weakness: No persistent intelligence, no compounding value, output is ephemeral
Option B: LinkedIn Graph as Persistent Data Source (alongside KB)¶
LinkedIn API (scheduled) → [LinkedIn Data Store] → Queryable by any capability
→ Feeds into Brand Voice enrichment
→ Relationship graph as persistent asset
Strengths: Compounding value, cross-capability intelligence, persistent relationship map Weakness: Requires full LinkedIn API access, ongoing sync, storage costs, LinkedIn API rate limits
Option C: LinkedIn Graph as Brand Sentiment Layer (modernized)¶
LinkedIn API → [Sentiment Processor] → Brand Voice enrichment
→ Audience-ICP delta tracking
→ Content effectiveness signals
→ Relationship warmth scores
Strengths: Differentiating, feeds the GTM engine, aligns with "schema is the moat" thesis Weakness: Most complex, requires LinkedIn Marketing Developer Platform approval, sentiment analysis adds latency
Recommendation: Start with Option A+, evolve toward Option C¶
Option A+ (Near-term, no API dependency):
- Keep the capability as-is but make the output persist as a knowledge artifact
- After execution, store analysis results in a linkedin_insights table or as KB documents
- Allow other capabilities (content generation, co-sell matching) to query past LinkedIn insights
- This creates compounding value without LinkedIn API access
Option C (Medium-term, requires API access): - Once LinkedIn developer access is complete, build a scheduled data sync - Process engagement data into a sentiment/audience profile that enriches Brand Voice - The relationship graph becomes a persistent warm-path asset for co-sell motions
Part 3: LinkedIn Developer Access Audit¶
Multi-App Architecture (Confirmed)¶
LinkedIn enforces app isolation on products that read org/member/page data. Products that read data from others are grayed out and cannot be added alongside any other product.
Isolation-required products (grayed out on existing app): - Community Management API - Member Data Portability API (3rd Party) - Pages Data Portability API - Verified on LinkedIn
Stackable products (blue "Request access" on existing app): - Advertising API - Lead Sync API - Live Events - Events Management API - Conversions API - LinkedIn Ad Library
This means Vell needs two LinkedIn developer apps:
App 1: Vell AI — Publishing + Marketing (existing)¶
- Client ID:
86lbyxc5vzdo04 - Created: April 15, 2025
- Purpose: Identity, outbound publishing, advertising, conversions, research
| Product | Tier | Status |
|---|---|---|
| Sign In with LinkedIn (OpenID Connect) | Standard | ADDED |
| Share on LinkedIn | Default | ADDED |
| Advertising API | Development | ADDED (approved 2026-03-03) |
| LinkedIn Ad Library | Default | ADDED (approved 2026-03-03, App ID 222715561) |
| Conversions API | Standard | SUBMITTED — awaiting review |
| Lead Sync API | Standard | Not added — optional |
| Events Management API | Standard | Not added — not needed |
| Live Events | Development | Not added — not needed |
Scopes (current): openid profile email w_member_social
Scopes (ready to add — Advertising API added): + r_ads r_ads_reporting
App 2: Vell AI — Community Intelligence (CREATED 2026-03-03)¶
- Client ID:
787zcjp7t3l55r - Created: March 3, 2026
- App Name (portal): "Vell AI Conversions API" — rename to "Vell AI — Community Intelligence" in Settings
- Purpose: Read org posts, follower demographics, engagement analytics
- CRITICAL: This app must have Community Management API as its only product
| Product | Tier | Status |
|---|---|---|
| Community Management API | Development | Request access next |
Scopes: r_organization_social w_organization_social rw_organization_admin w_member_social
Endpoints unlocked:
- GET /rest/posts — Read organization posts
- GET /rest/socialActions — Engagement data (likes, comments, shares)
- GET /rest/organizationalEntityFollowerStatistics — Follower demographics
- GET /rest/organizationPageStatistics — Page views, visitor demographics
- POST /rest/socialActions — React/comment on behalf of org
- GET /rest/socialMetadata — Aggregate engagement metrics
Dual-App OAuth Implications¶
Two LinkedIn apps = two OAuth authorization flows. This has real architectural impact:
Option 1: Sequential authorization — User connects App 1 (publishing), then separately connects App 2 (analytics). Two tokens stored per user.
Option 2: Single UX, dual redirect — One "Connect LinkedIn" button chains both authorizations. User sees two LinkedIn consent screens back-to-back.
Option 3: Conditional authorization — App 1 connects on social media setup. App 2 connects only when user enables LinkedIn Graph Analysis capability.
Recommendation: Option 3. Most users need publishing (App 1). Only users who want LinkedIn Graph Analysis need the analytics connection (App 2). This avoids unnecessary consent friction and aligns with the capability-based architecture.
Code impact:
- Linkedin.php needs to support two sets of credentials
- LinkedinController.php OAuth callback needs to route to the correct app
- SocialMediaPlatform model may need a purpose or app_type field
- social-media.php config needs a second LinkedIn entry (e.g., linkedin_analytics)
Current Product Status (as of 2026-03-03)¶
| LinkedIn API Product | Tier | App | Status | Action Needed |
|---|---|---|---|---|
| Sign In with LinkedIn | Standard | App 1 | ADDED | None |
| Share on LinkedIn | Default | App 1 | ADDED | None |
| Advertising API | Development | App 1 | ADDED | Add scopes r_ads r_ads_reporting to OAuth flow |
| LinkedIn Ad Library | Default | App 1 | ADDED | Integration built — test with live token |
| Conversions API | Standard | App 1 | SUBMITTED | Awaiting LinkedIn review |
| Lead Sync API | Standard | App 1 | NOT ADDED | Optional |
| Live Events | Development | App 1 | NOT ADDED | Not needed |
| Events Management API | Standard | App 1 | NOT ADDED | Not needed |
| Community Management API | Development | App 2 (787zcjp7t3l55r) |
CREATED — request access next | Request Community Management API as sole product |
| Member Data Portability API | Default | N/A | SKIPPED | Requires exclusive app, low priority |
| Pages Data Portability API | Standard | N/A | SKIPPED | Requires exclusive app |
| Verified on LinkedIn | Development | N/A | SKIPPED | Not needed |
Tier Definitions (Corrected)¶
LinkedIn's tier labels are misleading. "Default Tier" does NOT mean instant self-service:
- Default Tier: Still requires access request form with organization details, use case description, and LinkedIn review. Bound by API Terms of Use + Research API Program Terms. Not instant.
- Standard Tier: Requires access request form with use case justification
- Development Tier: Requires LinkedIn review via Access Request Form, use case justification, and approval
In practice, every product beyond Sign In requires a form submission and review.
Immediate Actions on App 1 (existing)¶
1. LinkedIn Ad Library (Default Tier) — Enables ad data search - Requires access request form with organization + use case details - Must agree to LinkedIn API Terms of Use + Research API Program Terms - Useful for competitor analysis and content intelligence - Use case to submit: "Enable AWS Marketplace ISV partners to analyze competitive ad positioning and content themes for GTM content strategy"
2. Conversions API (Standard Tier) — Enables attribution tracking - The marketplace correlation differentiator - Use case to submit: "Track conversion events from LinkedIn content engagement to AWS Marketplace listing views, demo requests, and Private Offers to measure social selling ROI"
3. Advertising API (Development Tier) — Enables audience demographics - Use case to submit: "Provide ISV partners with aggregate audience demographic insights to measure ICP alignment of their LinkedIn content strategy"
Create App 2: Community Intelligence¶
4. App 2 created: 787zcjp7t3l55r (2026-03-03)
- Current name: "Vell AI Conversions API" — rename to "Vell AI — Community Intelligence"
- LinkedIn Page: Same company page as App 1
- Only product: Community Management API (request access next)
5. Request Community Management API on App 2 - Use case to submit: "Read organization post analytics, follower demographics, and engagement metrics to provide ISV partners with LinkedIn audience intelligence for GTM content strategy and social selling optimization"
Application Requirements (for Development Tier products)¶
LinkedIn requires: 1. Company Page with active presence 2. App use case description — how you'll use the data 3. Privacy policy URL — must describe LinkedIn data handling 4. Terms of service URL — must cover social data usage 5. OAuth redirect URLs — already configured for App 1; need new redirect for App 2 6. Rate limit justification — expected API call volume 7. Data retention policy — how long you keep LinkedIn data
OAuth Config — Dual App Setup¶
social-media.php will need to support two LinkedIn configurations:
// App 1: Publishing + Marketing (existing)
'linkedin' => [
'app_id' => 'LINKEDIN_APP_ID',
'app_secret' => 'LINKEDIN_APP_SECRET',
'redirect_uri' => '/social-media/oauth/callback/linkedin',
'scopes' => ['openid', 'profile', 'email', 'w_member_social'],
// ...existing config...
],
// App 2: Community Intelligence (new — analytics/reading)
'linkedin_analytics' => [
'app_id' => 'LINKEDIN_ANALYTICS_APP_ID',
'app_secret' => 'LINKEDIN_ANALYTICS_APP_SECRET',
'redirect_uri' => '/social-media/oauth/callback/linkedin-analytics',
'scopes' => ['r_organization_social', 'w_organization_social', 'rw_organization_admin'],
// ...
],
Note: Current config has scopes as a single space-delimited string ('openid profile email w_member_social'). This should be updated regardless of dual-app setup.
What LinkedIn Will NOT Provide (API Limitations)¶
Even with full API access, LinkedIn restricts: - Connection graph traversal — You cannot enumerate a user's connections - Engager identity — You get aggregate demographics, not individual profiles of who liked/commented - Cross-account relationship mapping — You can't map paths between arbitrary users - Real-time webhooks — LinkedIn doesn't push data; you must poll
Impact on capability claims:
| Capability Claim | Feasible via API? | Alternative |
|---|---|---|
| "See which posts drive engagement" | YES — post analytics available | — |
| "Map warm paths to key accounts" | PARTIAL — no connection graph traversal | Use comment/engagement overlap as proxy |
| "Understand your real audience" | YES (aggregate) — follower demographics available | — |
| "Social selling at scale" | PARTIAL — individual engager profiles not available | Use aggregate patterns + manual data input |
The Relationship Graph Mapping (15 credits) capability as described in the docs — "warm introduction paths with relationship strength scores" — cannot be fully implemented via LinkedIn's API. The warm-path examples in the feature docs (e.g., "You → Sarah Chen → Mike Johnson") would require connection graph data that LinkedIn does not expose.
Honest alternative: Relationship intelligence based on engagement overlap — who comments on both your posts and the target account's posts. This is achievable and still valuable, but should be positioned differently than "graph mapping."
Part 4: Recent Executions — Do They Relate to LinkedIn?¶
Short answer: Probably not.¶
The executions table (ext_content_manager_agent_executions) tracks ALL agent capability executions — content generation, SEO analysis, competitor analysis, marketplace optimization, etc. The "Recent Executions" UI section shows executions sorted by created_at DESC across all capability types.
To confirm, you'd need to filter executions where the agent's capabilities include linkedin_graph_analysis and the step_results reference that capability. Without live database access, the most likely explanation is that recent executions are from other capabilities (content generation, SEO, marketplace listing optimization are the most commonly used).
To verify: Check the task_description or step_results JSON for any execution to see if it references LinkedIn analysis.
Part 5: Alignment with Portability Audit¶
The PARTNER_OUTPUT_PORTABILITY_AUDIT.md classifies social media as "Dare to Be Bad" — a supporting capability, not a differentiator:
Dare to Be Bad (Supports): Generic content generation, social media, brand monitoring
And rates the competitive moat: - General AI Content Generation: 2/10 (commodity) - "Deployed on AWS": 3/10 (table stakes)
Meanwhile, the stars — the capabilities to double down on: - GTM Content Schema (10/10) - First Call Enrichment (8/10) - Multi-Persona Dry-Run Simulation (9/10) - Agentic Workflow + MCP (8/10)
Where LinkedIn Graph Fits in This Framework¶
The LinkedIn Graph capability straddles two categories:
If it's "analyze LinkedIn posts and engagement" → Dare to Be Bad (every social media tool does this)
If it's "correlate LinkedIn activity with AWS Marketplace pipeline" → Potential Star (nobody else does this)
The differentiating value is the correlation — connecting social engagement to marketplace conversions. That's the Content-to-Marketplace Correlation analysis type (15 credits). The other four analysis types are commodity.
Strategic Recommendation¶
Invest in the correlation, not the social analytics. The post performance and audience insights analysis types are table stakes — Hootsuite, Sprout Social, and LinkedIn's native analytics already do this. What nobody else does is correlate LinkedIn engagement with AWS Marketplace conversion events.
The LinkedIn Graph capability should be repositioned: - De-emphasize: Generic post performance, audience demographics (commodity) - Emphasize: Content-to-Marketplace attribution, co-sell relationship signals - Integrate: Feed correlation insights into GTM Content Schema (the crown jewel from the portability audit)
Part 6: Implementation Priority Checklist¶
TODAY — App 1 (86lbyxc5vzdo04)¶
- Share on LinkedIn product — ADDED
- LinkedIn Ad Library — ADDED (approved 2026-03-03)
- Advertising API — ADDED (approved 2026-03-03)
- Conversions API — SUBMITTED, awaiting LinkedIn review
- Test that publishing flow works now that Share on LinkedIn is active
- Test Ad Library endpoint with live bearer token
TODAY — App 2 (787zcjp7t3l55r) — CREATED 2026-03-03¶
- Create LinkedIn developer app
- Rename app from "Vell AI Conversions API" → "Vell AI — Community Intelligence"
- Request Community Management API as the sole product
- Configure redirect URI:
/social-media/oauth/callback/linkedin-analytics
THIS WEEK (Code changes — no API approval required)¶
- Add
linkedin_analyticsconfig block tosocial-media.phpfor App 2 - Add
linkedin_analyticsconfig block tosocial-media.php - Add
linkedin_analyticstoPlatformEnum(not in publishing UItoArray()/all()) - Create
LinkedinAnalyticsController.phpOAuth callback for App 2 - Register routes:
redirect/linkedin-analytics,callback/linkedin-analytics - Add
searchAdLibrary()toLinkedin.php - Create
LinkedInAdLibraryService.phpfor competitor ad research - Add
competitor_ad_analysistype (10 credits) toLinkedInGraphCapability.php - Add App 2 env vars in admin settings:
LINKEDIN_ANALYTICS_APP_ID,LINKEDIN_ANALYTICS_APP_SECRET - Persist LinkedIn Graph Analysis output as queryable knowledge artifacts
- Add
linkedin_insightsas a context source inBrandVoiceContextBuilder - Audit feature docs to align claims with what's actually deliverable via API
AFTER COMMUNITY MANAGEMENT API APPROVAL (App 2)¶
- Implement
getOrganizationPosts()inLinkedin.phpusing App 2 tokens - Implement
getFollowerDemographics()using App 2 tokens - Implement
getPostAnalyticsBatch()for bulk post analysis - Build scheduled data sync for connected LinkedIn org accounts
- Replace "provided data" prompt pattern with actual API data in
LinkedInGraphCapability.php - Wire Post Performance and Audience Insights analysis types to real data
AFTER ADVERTISING API APPROVAL (App 1) — APPROVED 2026-03-03¶
- Add
r_adsandr_ads_reportingto App 1 OAuth scopes - Implement audience demographic retrieval from ad analytics
- Wire ICP Alignment analysis type to real audience data
- Build aggregate demographic profiles for brand sentiment layer
AFTER CONVERSIONS API APPROVAL (App 1 — The Differentiator)¶
- Implement conversion event ingestion from LinkedIn
- Build Content-to-Marketplace attribution pipeline
- Correlate LinkedIn post engagement with AWS Marketplace conversion events
- Wire Content-to-Marketplace Correlation analysis type to real attribution data
- Feed correlation insights back into GTM Content Schema
MEDIUM-TERM (Persistent Intelligence Layer)¶
- Build persistent LinkedIn data store (engagement history, audience snapshots)
- Implement engagement-overlap relationship intelligence (realistic alternative to graph traversal)
- Create brand sentiment layer from LinkedIn engagement patterns
- Feed sentiment signals into Brand Voice context for content generation
- Build time-series audience-ICP delta tracking
Part 7: File Reference¶
| File | Purpose | Status |
|---|---|---|
app/Extensions/ContentManager/System/Services/Capabilities/LinkedInGraphCapability.php |
Capability handler | Ad Library wired; other types prompt-only |
app/Extensions/SocialMedia/System/Helpers/Linkedin.php |
LinkedIn API client | Publishing + analytics + Ad Library search |
app/Extensions/SocialMedia/System/Services/LinkedInAdLibraryService.php |
Ad Library research service | NEW — competitor ad analysis |
app/Extensions/SocialMedia/config/social-media.php |
OAuth config | Dual-app: linkedin + linkedin_analytics |
app/Extensions/SocialMedia/System/Http/Controllers/Oauth/LinkedinController.php |
App 1 OAuth flow | Publishing (existing) |
app/Extensions/SocialMedia/System/Http/Controllers/Oauth/LinkedinAnalyticsController.php |
App 2 OAuth flow | NEW — analytics connection |
app/Extensions/SocialMedia/System/Enums/PlatformEnum.php |
Platform enum | Added linkedin_analytics case |
app/Extensions/SocialMedia/System/SocialMediaServiceProvider.php |
Route registration | Added analytics OAuth routes |
app/Extensions/ContentManager/System/Services/AgentCore/CapabilityRegistry.php |
Capability registration | LinkedIn registered at line ~486 |
app/Extensions/ContentManager/System/Services/AgentCore/BrandVoiceContextBuilder.php |
Context builder | Feeds into LinkedIn capability, but not reverse |
docs/features/linkedin-insights.md |
Public feature docs | Claims exceed current API capability |
PARTNER_OUTPUT_PORTABILITY_AUDIT.md |
Strategic framework | Classifies social media as "Dare to Be Bad" |