A production-ready Next.js application that provides an internal API for extracting comprehensive LinkedIn profile data, wrapped in a premium interactive dashboard.
This scraper is designed to bypass traditional heavy headless browsers (like Puppeteer) by directly invoking LinkedIn's internal React Server Component (RSC) and SDUI (Server Driven UI) APIs using authenticated session cookies.
- RSC Flight Parsing: Decodes native React flight records, resolves
$Lxnode references dynamically, and traverses the underlying UI data tree without fragile DOM parsing. - Robust Caching: Uses Upstash Redis exclusively to cache extraction payloads (
CACHE_TTL_SECONDS = 3600), minimizing redundant requests to LinkedIn servers and avoiding account bans. - Sliding Window Rate Limiting: Enforces strict IP-based rate limiting (10 requests per minute) handled purely at the edge via Upstash Redis.
- Interactive Dashboard: Beautiful, responsive Bento Grid UI powered by Framer Motion for spring-physics interactions, utilizing zero external UI component libraries for absolute control.
- Framework: Next.js 14 (App Router)
- Language: TypeScript
- State & Edge: Upstash Redis
- Styling: Vanilla CSS (Custom Pastel Palette)
- Animations: Framer Motion
-
Clone the repository:
git clone https://github.com/vpn-cli/linkedin-scraper.git cd linkedin-scraper -
Install dependencies:
npm install
-
Configure Environment Variables: Rename
.env.exampleto.envand configure:# Authentication LINKEDIN_LI_AT=your_li_at_cookie LINKEDIN_JSESSIONID=your_jsessionid_cookie # Redis Configuration UPSTASH_REDIS_REST_URL=your_upstash_url UPSTASH_REDIS_REST_TOKEN=your_upstash_token # Thresholds CACHE_TTL_SECONDS=3600 RATE_LIMIT_WINDOW_SECONDS=60 RATE_LIMIT_MAX_REQUESTS=10
-
Run Locally:
npm run dev
-
Deploy to Vercel: The application is fully compatible with Vercel's edge deployment. Simply import your repository into the Vercel dashboard and paste the ENVs above to instantly generate your hosted API.
POST /api/profile
Extracts data for a target LinkedIn Vanity URL (e.g. https://www.linkedin.com/in/arthur-bedel/).
{
"url": "https://www.linkedin.com/in/williamhgates/"
}export interface ProfileResponse {
profile: {
name: string;
headline: string;
location: string;
about: string;
profileImage: string | null;
backgroundImage: string | null;
};
experience: ExperienceItem[];
education: EducationItem[];
skills: string[];
certifications: CertificationItem[];
languages: string[];
featured: FeaturedItem[];
services: string[];
errors?: ErrorItem[];
}Due to the time constraints of this challenge and the extreme obfuscation of LinkedIn's internal SDUI payload, the deep positional array mappings for specific profile fields were left stubbed out. The architectural pipeline—including authentication, Redis caching, robust edge rate-limiting, and generic RSC component decoupling—is fully complete and production-ready.
To finalize the API bridging, you must run the included diagnostic scripts locally against your intercepted raw JSON payloads.
- Locate your marker: Open the provided
debug-com.linkedin.sdui...jsonfiles. - Run the Diagnostic Tracer: Execute the included standalone generic path-finding script:
npx tsx scripts/generic-tracer.ts debug-com.linkedin.sdui.generated.profile.dsl.impl.profileCardsExperienceOnly.json "Your Target String" - Map the Output: The script will print the exact nested array path (e.g.
root[3]["children"][1]...) to the string you are looking for. - Update the Parser: Open
lib/linkedin/parser.tsand replace the stubbed// TODOsections inparseExperience,parseProfileHeader, andparseAboutwith the precise traversal logic discovered in Step 3. - Redeploy: Push your changes to the
mainbranch. Vercel will automatically rebuild the API with your live extraction mappings!
Developed as part of an Engineering Security Challenge.