How the LinkedIn Search Integration Works in the AI Job Search Framework

The AI Job Search framework fetches live LinkedIn job listings through a zero-dependency CLI skill that queries public jobs-guest endpoints without authentication, parsing HTML responses into structured markdown for downstream AI processing.

The LinkedIn search integration is a core component of the MadsLorentzen/ai-job-search repository, enabling autonomous job discovery without API keys or browser automation. This self-contained skill resides under .agents/skills/linkedin-search and interfaces directly with the framework's generic job-scraper orchestration layer.

Architectural Components

The integration follows a modular, skill-based architecture designed for minimal footprint and maximum portability.

Skill Registry and Descriptor

The framework discovers the LinkedIn capability through .agents/skills/linkedin-search/SKILL.md, which declares the skill's interface, supported flags, and execution context to the AI agent. This descriptor allows the framework to route user requests for LinkedIn listings to the appropriate handler without hard-coded dependencies.

CLI Entrypoint and Validation

The primary execution logic lives in .agents/skills/linkedin-search/cli/src/cli.ts. This TypeScript entrypoint parses command-line arguments, validates the required --location parameter via helpers.validateLocation, and orchestrates the HTTP request lifecycle. The CLI is designed as a standalone Node.js package with zero runtime dependencies beyond the standard library and node-html-parser, enabling installation and execution across JavaScript runtimes like Node.js or Bun.

Helper Utilities and URL Construction

Low-level networking and data extraction logic is encapsulated in .agents/skills/linkedin-search/cli/src/helpers.ts. This module constructs requests to LinkedIn's public https://www.linkedin.com/jobs-guest/search endpoint, implements the convertJobAgeToSeconds function to map human-readable age filters (e.g., "last 120 minutes") to LinkedIn's internal f_TPR query parameter, and parses HTML responses to extract job IDs, titles, companies, locations, descriptions, and posting dates.

Integration with Job Scraper

The generic job-scraper skill located at .claude/skills/job-scraper/SKILL.md registers linkedin.com/jobs as a supported source. When users request LinkedIn-specific searches through the framework's /search command, the orchestrator delegates to the LinkedIn Search CLI, streams the resulting markdown table or JSON back into the conversational context, and passes structured job metadata to subsequent pipeline stages like /rank and /apply.

Data Flow and Execution Pipeline

The LinkedIn search skill operates through a deterministic five-stage pipeline:

  1. Invocation – The user submits a search query via the framework's /search command or directly invokes the CLI with the -l (location) flag, such as -l "Berlin, Germany".

  2. Request Construction – The CLI builds a URL targeting LinkedIn's jobs-guest endpoint, appending query parameters for location and, if specified, time-based filters using the f_TPR parameter derived from --jobage-minutes values.

  3. HTTP Fetching – The system issues an unauthenticated GET request against the public endpoint. Exponential back-off retry logic handles HTTP 429 (rate limit) and 5xx server errors to respect LinkedIn's infrastructure.

  4. HTML Parsing – Using node-html-parser, the helpers.ts module traverses the returned HTML document, locates job card elements, and extracts structured fields including job ID, title, company name, location, description snippet, and relative posting age.

  5. Output Formatting – Extracted data is serialized into either markdown tables (default) or JSON arrays based on the --output flag, then ingested by the framework's AI pipeline for candidate-profile matching and application preparation.

Key Implementation Files

Understanding the source structure requires familiarity with these specific file paths:

Usage Examples

Execute a basic search for jobs in Berlin with default markdown output:

linkedin-cli -l "Berlin, Germany"

Retrieve recent remote positions posted within the last 120 minutes as JSON:

linkedin-cli -l "Remote" --output json --jobage-minutes 120

Programmatic invocation within the framework's TypeScript codebase:

import { runLinkedInSearch } from "./.agents/skills/linkedin-search/cli/src/cli";

const results = await runLinkedInSearch({
  location: "London, United Kingdom",
  output: "markdown",
  jobAgeMinutes: 0
});

// Returns markdown table for AI pipeline consumption
console.log(results);

Summary

  • The LinkedIn search skill queries public jobs-guest endpoints requiring no authentication or API keys.
  • Core logic resides in .agents/skills/linkedin-search/cli/src/cli.ts with helper utilities in helpers.ts.
  • The integration supports filtering by location and posting age through the --jobage-minutes flag mapped to LinkedIn's f_TPR parameter.
  • Zero runtime dependencies ensure portable execution across JavaScript runtimes.
  • The skill connects to the broader framework via .claude/skills/job-scraper/SKILL.md for seamless pipeline integration.
  • Built-in exponential back-off handles rate limiting, while documentation enforces personal-use-only restrictions.

Frequently Asked Questions

Does the LinkedIn search integration require API credentials or a LinkedIn account?

No. The skill queries LinkedIn's public jobs-guest endpoints, which return HTML job listings accessible without authentication, cookies, or API keys. This design deliberately avoids credential management while respecting LinkedIn's Terms of Service for personal, low-volume usage.

How does the framework handle LinkedIn's anti-scraping measures and rate limits?

The CLI implements exponential back-off retry logic for HTTP 429 (Too Many Requests) and 5xx server errors. Additionally, the README.md and CLI banner enforce a "personal use only" policy, discouraging automated bulk scraping that would trigger aggressive rate limiting or IP blocking.

What data fields are extracted from LinkedIn job postings?

The helpers.ts parsing logic extracts job ID, title, company name, location, description snippet, and posting date/age from LinkedIn's HTML job cards. These fields are normalized into markdown tables or JSON structures for downstream AI processing in the ranking and application stages.

Can I filter results by how recently jobs were posted?

Yes. The --jobage-minutes flag accepts an integer value that convertJobAgeToSeconds transforms into LinkedIn's internal f_TPR query parameter. For example, passing --jobage-minutes 120 restricts results to positions posted within the last two hours.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →