# How to Engage Passive Candidates: A Research-First LinkedIn Playbook

How to engage passive candidates on LinkedIn – research before the first touch, a short follow-up sequence, and AI drafts a recruiter approves before sending.

To engage passive candidates – people who are not applying for jobs but would move for the right role – you need a reason that is about them, not a job ad. This guide covers who counts as passive, why most recruiter messages get ignored, what to research before the first touch, a follow-up sequence to test, and how to let an AI agent do the research and drafting while a recruiter approves every message.

> **The short version.** Passive candidates are people who are not applying for jobs but would consider the right move – in Gallup's late-2025 poll, 40% of U.S. employees were watching for opportunities without actively looking, against 11% actively searching. They answer a specific reason, not a job ad. So research each person before the first touch – a recent post, a career move, a project – and pair one true detail about them with one real detail about the role: the problem, the setup, the pay you can share. Reach them through the channel your relationship allows. A sensible starting point to test is a first message once they accept, then two follow-ups about a week apart, stopping the moment they reply. When someone says "not now", agree when to come back. An AI agent can do the per-person research and draft each message from your role brief, as long as a recruiter approves every message before it goes out.

## What is a passive candidate?

A passive candidate is someone who is employed, not applying for jobs, and open to the right move. Active candidates are the opposite: they search and apply. Gallup asks U.S. employees the question directly – "To what extent are you currently looking for a different job than the one you have now?" – and the answers split like this:

| Gallup's answer option | Share of U.S. employees, Q4 2025 | What it means for outreach (editorial) |
| --- | --- | --- |
| Actively looking for another job | 11% | Job posts and applications already reach them |
| Watching for opportunities, but not actively looking | 40% | The core of outreach – open, but not searching |
| Not looking for another job | About 49% | Can still consider the right role; the reason has to be stronger and the timing better |

The shares come from Gallup's poll of 22,368 U.S. employees, fielded October 30 – November 13, 2025 ([Gallup](https://www.gallup.com/workplace/703280/worker-thriving-declines-job-market-pessimism-grows.aspx)); its tracker put the combined share watching or actively seeking at 53% in August 2026 ([Gallup](https://www.gallup.com/467702/indicator-employee-retention-attraction.aspx)). Gallup measures whether people are looking, not whether they will answer a recruiter – the third column is our reading, not Gallup's.

The figure most articles quote – "70% of the global workforce is passive talent" – comes from LinkedIn's 2015 Global Talent Trends survey of 20,931 members. It is more than ten years old, so use it with its date.

## Why passive candidates ignore recruiter messages

LinkedIn's own data on recruiter InMails points at the usual reasons:

- **Bulk messages.** "InMails that are sent individually see response rates roughly 15% higher than InMails sent in bulk" – from LinkedIn's analysis of tens of millions of recruiter InMails sent between May 2021 and April 2022 ([LinkedIn Talent Blog](https://www.linkedin.com/business/talent/blog/talent-strategy/these-inmails-get-best-response-rates)).
- **Long messages.** "The response rate for the shortest InMails is 22% higher than the average response rate for all InMails" – the shortest being under 400 characters (same study).
- **No connection to the company.** "Candidates are 46% more likely to accept an InMail if they're already connected to someone at your company" ([LinkedIn Talent Blog](https://www.linkedin.com/business/talent/blog/talent-acquisition/how-to-recruit-passive-candidates)).

The rest is editorial, but consistent with that data: a pasted job description, no reason why this person, a message in their busiest month, and follow-ups that never stop.

## Where to find passive candidates on LinkedIn

Search cannot tell you who is open. Standard and Sales Navigator search have no job-seeking filter, and a member's recruiters-only Open to Work setting is visible only to people using LinkedIn Recruiter ([LinkedIn Help](https://www.linkedin.com/help/linkedin/answer/a507508)) – so a profile without the green frame tells you nothing. Search by role, current and past company, school and location, then judge from the profile.

Turning a vacancy into that search and an evidence-backed shortlist is covered in [AI candidate sourcing on LinkedIn](/guides/ai-candidate-sourcing-linkedin); search operators are in [LinkedIn Boolean search](/guides/linkedin-boolean-search), and mapping a whole market is in [talent mapping for recruitment](/guides/talent-mapping-recruitment). This guide starts where the shortlist ends.

## Research each person before the first touch

What you can say depends on what the profile shows. This table is editorial guidance:

| Signal on the profile | What it lets you say | Where you read it |
| --- | --- | --- |
| A recent post or comment | The point they made, and how it connects to the role's problem | Their recent activity |
| A talk, article or open-source project | The specific work, by name | Featured section, posts, links |
| A new role, under about six months | Congratulations – no pitch yet; note when to come back | Experience: start date |
| Several years in the same role | What a next step could look like – more scope, a new problem | Experience: months in the role |
| A shared employer or school | The overlap, stated plainly | Experience and education |

Done by hand, this takes minutes per person – Juicebox's guide budgets five to ten minutes for each top-tier candidate. That reading and the first draft are the parts to hand to an AI agent, further down.

## How to reach passive candidates: the first message and the follow-ups

The channel depends on your relationship:

- **Already connected (1st degree):** send a message.
- **2nd or 3rd degree:** send a connection request – with a note only when you have a specific reason – and message once they accept. A free account can add a note to three requests a month, up to 200 characters; Premium removes the monthly cap ([LinkedIn Help](https://www.linkedin.com/help/linkedin/answer/a563153)). Recruiting note examples are in [LinkedIn connection request message examples](/guides/linkedin-connection-request-message).
- **Outside your network, on a paid plan:** InMail needs Premium, Sales Navigator or Recruiter, and runs on credits that come back when the recipient accepts, declines or replies within 90 days ([LinkedIn Help](https://www.linkedin.com/help/linkedin/answer/a541643)) – the details are in the [LinkedIn InMail guide](/guides/linkedin-inmail).

What the first message carries:

1. **One true detail about them** – the post, the project, the move.
2. **One verified detail about the role that connects to it** – the actual problem, the setup (remote, hybrid, location), the pay you are allowed to share. LinkedIn's Talent Blog lists what candidates weigh: "Compensation", "Career and personal growth opportunities", "Intrinsic enjoyment of the work", "Professional autonomy", "Flexible work opportunities" and "Mission and values alignment".
3. **Why now**, in a clause.
4. **One small ask** – a 15-minute call, not a CV.

### A starting cadence to test

This is editorial guidance, not a measured LinkedIn schedule:

1. Connection request – a note only if you have a specific reason.
2. The first message, once they accept.
3. Follow-up one, about a week later, adding something new – a detail about the team, or an answer to a question their post raised.
4. Follow-up two, about a week after that – a short close-the-loop.
5. Stop. Any reply – yes, no or later – ends the sequence.

The published follow-up data comes from email, not LinkedIn. In Gem's analysis of over 4 million recruiting email sequences (March 2023 – February 2024), the cumulative reply rate rose from 11.7% after the first email to 22.6% after the fifth and then flattened; recruiters typically waited six days between emails. Ashby's analysis of 500,000+ email sequences (January 2022 – January 2024) found replies plateau around 23% after three emails, with most campaigns spacing emails four days apart. And in LinkedIn's InMail study, 90% of the responses that arrived came within a week. None of this tests a LinkedIn sequence – it is why a week between touches and a stop after the third message are a reasonable place to start.

### One worked sequence

For an invented candidate, Wei, a staff data engineer at Fabrikam who posted about moving the team's pipeline to Flink, and an invented role at Northwind that owns the same migration:

| Step | Message | Characters |
| --- | --- | --- |
| Connection note | Hi Wei – your post on moving Fabrikam's pipeline to Flink was the clearest write-up of that migration I've read. I recruit for data teams and would be glad to connect. | 167 |
| First message, after Wei accepts | Thanks for connecting, Wei. Why I reached out: Northwind is starting the same Kafka-to-Flink move you described, and the staff engineer who owns it will set the design. It's fully remote within the EU, €110–130k. Would a 15-minute call next week be worth it, even just to compare notes? | 286 |
| Follow-up one, about a week later | Hi Wei – one detail I left out: the team is four engineers, and the migration has a fixed date because the old cluster is retired next autumn. Happy to send the architecture outline if that's more useful than a call. | 216 |
| Follow-up two, about a week after that | Last note from me, Wei. If the timing is wrong, no problem at all – tell me when would be better and I'll come back then. | 121 |

The first message pairs Wei's post with the role's real problem, its setup and its pay band, and asks for one small thing. Nothing in the sequence is a pasted job description.

## Let an AI agent research and draft – you approve every message

The research and the first draft are where the time goes, and both suit an AI model – if it gets the right inputs and a recruiter keeps the send button.

**Two inputs:**

- **A role brief you write once per vacancy** – the company, the actual problem or scope, location and workplace arrangement, the compensation you are allowed to share, and what makes the role worth a move.
- **Evidence per person** – current roles with months in each, earlier roles, and recent posts with their dates. [Linked API](/docs/action-st-open-person-page) reads these from the profile on your own LinkedIn account: `fetchPerson` with experience and posts in code, below, or the `fetch_person` tool for an AI agent.

**An illustrative prompt:**

> You draft LinkedIn recruiting messages. Inputs: one role brief and one research packet per person. For each person, write a connection note (under 200 characters, or blank), a first message (under 400 characters) and two short follow-ups. Rules: use only facts from the role brief and the packet, and never invent; tie one true detail about the person to one verified detail about the role; no salary or benefits that are not in the brief, and no pasted job description; one small ask. If nothing in the packet links this person to this role, answer SKIP.

**Then review every draft.** A recruiter reads each one and approves, edits or skips it before anything is sent. LinkedIn builds its own tool the same way: with AI-Assisted Messages in Recruiter, "you are responsible for reviewing the message draft for accuracy and making any necessary edits" ([Recruiter Help](https://www.linkedin.com/help/recruiter/answer/a1480502)).

Hosted tools draft recruiting messages too, with different review steps:

| Tool | Best for | Review, as documented |
| --- | --- | --- |
| LinkedIn Recruiter – AI-Assisted Messages | Teams already on Recruiter seats | The recruiter reviews each draft and sends it |
| LinkedIn Hiring Assistant | Recruiter customers delegating sourcing | Review each draft and send one by one or in bulk – or turn on instant outreach for a project, which drafts, sends and follows up automatically |
| Gem | In-house teams running email sequences from a recruiting CRM | With its AI custom token, each recipient must be reviewed before the sequence sends |
| SeekOut | Sourcing teams writing email sequences | You review each AI-written message in per-candidate mode, or the shared template, before the sequence starts |
| hireEZ EZ Agent | High-volume teams across email, text and InMail | "Recruiters can review every outreach message before it's sent", per hireEZ's product explainer |
| Juicebox | Small teams wanting search plus email on autopilot | You review the sequence before the agent uses it; lead approval can be manual or automatic |
| Linked API | Teams that want the loop on their own LinkedIn account, in their own code or agent | The approval gate is whatever your agent instructions or code enforce – nothing is sent until they call a send action |

## Build the research step in code – or let an agent run it

The script reads `shortlist.json` – the profile URLs from your shortlist – and writes one research packet per person to `packets.json` for the drafting step: name, headline, every current role with months in it, and original posts from the last 90 days with their dates.

```typescript
import { readFile, writeFile } from "node:fs/promises";
import LinkedApi, { LinkedApiError } from "@linkedapi/node";

const linkedapi = new LinkedApi({
  linkedApiToken: "your-linked-api-token",
  identificationToken: "your-identification-token",
});

const POSTS_SINCE = new Date(Date.now() - 90 * 24 * 60 * 60 * 1000).toISOString().replace(/\.\d{3}Z$/, "Z");

interface CurrentRole {
  position: string;
  companyName: string;
  monthsInRole: number;
}

interface RecentPost {
  time: string;
  url: string;
  text: string;
}

interface ResearchPacket {
  personUrl: string;
  status: "researched" | "partial" | "retry";
  name?: string;
  headline?: string;
  currentRoles?: Array<CurrentRole>;
  recentPosts?: Array<RecentPost>;
  detail?: string;
}

async function research(personUrl: string): Promise<ResearchPacket> {
  try {
    const workflow = await linkedapi.fetchPerson.execute({
      personUrl,
      retrieveExperience: true,
      retrievePosts: true,
      postsRetrievalConfig: { limit: 5, since: POSTS_SINCE },
    });
    const { data, errors } = await linkedapi.fetchPerson.result(workflow.workflowId);
    if (!data) {
      const [error] = errors;
      return { personUrl, status: "retry", detail: error ? error.message : "no profile data" };
    }
    const { name, headline, experiences = [], posts = [] } = data;
    const detail = errors.map(({ message }) => message).join("; ");
    return {
      personUrl,
      status: detail ? "partial" : "researched",
      name,
      headline,
      currentRoles: experiences
        .filter((role) => role.endTime === null)
        .map(({ position, companyName, duration }) => ({ position, companyName, monthsInRole: duration })),
      recentPosts: posts
        .filter((post) => post.type === "original" && post.text)
        .map(({ time, url, text }) => ({ time, url, text: text ?? "" })),
      detail,
    };
  } catch (caught) {
    if (caught instanceof LinkedApiError) {
      return { personUrl, status: "retry", detail: caught.message };
    }
    throw caught;
  }
}

async function main(): Promise<void> {
  const shortlist: Array<string> = JSON.parse(await readFile("shortlist.json", "utf8"));
  const packets: Array<ResearchPacket> = [];
  for (const personUrl of shortlist) {
    packets.push(await research(personUrl));
  }
  await writeFile("packets.json", JSON.stringify(packets, null, 2));
  const toCheck = packets.filter((packet) => packet.status !== "researched").length;
  console.log(`${packets.length - toCheck} researched, ${toCheck} to check or retry`);
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});
```

```python
import json
from datetime import datetime, timedelta, timezone
from pathlib import Path

from linkedapi import FetchPersonParams, LimitSinceParams, LinkedApi, LinkedApiConfig, LinkedApiError

linkedapi = LinkedApi(
    LinkedApiConfig(
        linked_api_token="your-linked-api-token",
        identification_token="your-identification-token",
    )
)

POSTS_SINCE = (datetime.now(timezone.utc) - timedelta(days=90)).strftime("%Y-%m-%dT%H:%M:%SZ")


def research(person_url: str) -> dict:
    try:
        workflow = linkedapi.fetch_person.execute(
            FetchPersonParams(
                person_url=person_url,
                retrieve_experience=True,
                retrieve_posts=True,
                posts_retrieval_config=LimitSinceParams(limit=5, since=POSTS_SINCE),
            )
        )
        result = linkedapi.fetch_person.result(workflow.workflow_id)
        person = result.data
        if person is None:
            detail = result.errors[0].message if result.errors else "no profile data"
            return {"personUrl": person_url, "status": "retry", "detail": detail}
        detail = "; ".join(error.message for error in result.errors)
        return {
            "personUrl": person_url,
            "status": "partial" if detail else "researched",
            "name": person.name,
            "headline": person.headline,
            "currentRoles": [
                {"position": role.position, "companyName": role.company_name, "monthsInRole": role.duration}
                for role in person.experiences or []
                if role.end_time is None
            ],
            "recentPosts": [
                {"time": post.time, "url": post.url, "text": post.text}
                for post in person.posts or []
                if post.type == "original" and post.text
            ],
            "detail": detail,
        }
    except LinkedApiError as caught:
        return {"personUrl": person_url, "status": "retry", "detail": caught.message}


shortlist = json.loads(Path("shortlist.json").read_text())
packets = [research(person_url) for person_url in shortlist]
Path("packets.json").write_text(json.dumps(packets, indent=2, ensure_ascii=False))
to_check = sum(1 for packet in packets if packet["status"] != "researched")
print(f"{len(packets) - to_check} researched, {to_check} to check or retry")
```

How to read the packets:

- **Every current role is kept.** A person can hold more than one, so the packet lists them all instead of guessing which matters.
- **`partial`** means the profile came back but part of it did not – the posts, say – so an empty post list is not mistaken for a quiet profile.
- **`retry`** covers a profile that could not be read and a request that failed or timed out; the run carries on with the next person.

Approved notes and messages go out with `sendConnectionRequest` and [`sendMessage`](/docs/action-st-send-message), each run in your account's dedicated cloud browser at a human pace, within the per-account limits you set ([admin limits](/docs/admin-limits)). The full send loop, with LinkedIn's note errors handled, is in the [connection request message guide](/guides/linkedin-connection-request-message), and message mechanics are in [how to automate LinkedIn messages](/guides/how-to-automate-linkedin-messages). To stop the follow-ups when someone answers, [inbox monitoring](/docs/monitoring-inbox) sends a [webhook event](/docs/webhook-event-types) for each new message – mark that person as replied and drop their pending follow-ups.

An AI agent with the [MCP server](/mcp/available-tools), the [CLI](/cli/getting-started) or a ready-made [skill](/skills) can run the same loop from a plain-language ask: read each profile with `fetch_person`, show you the drafts against your role brief, and call `send_connection_request` or `send_message` only for the ones you approve. Keep that approval step in your instructions. What else an agent can run on your account is in [LinkedIn AI agents](/guides/linkedin-ai-agent).

Read only what the message needs. The privacy note in the [talent mapping guide](/guides/talent-mapping-recruitment) applies here too.

## Keep "not now" candidates warm

- **Agree when to come back.** Ask what is holding them back; the date should come from them, not from a fixed interval.
- **LinkedIn's examples, not a rule.** Its Talent Blog suggests that for someone waiting to launch a major project or reach a personal milestone, "you might reach out in six months to a year to follow up", and for someone who just started a new job, a year or two.
- **Re-read the profile before you return.** A new role, a new post or a finished project is the next reason to write.
- **Keep them in view.** [Network monitoring](/docs/monitoring-network) shows who accepted your requests, so "not now" contacts stay in your network where their updates reach you.

## Frequently Asked Questions (FAQ)

#### What is a passive candidate?

Someone who is employed and not applying for jobs but would consider the right move. In Gallup's late-2025 poll of U.S. employees, 40% were watching for opportunities without actively looking, and 11% were actively searching.

#### What percentage of the workforce is passive?

The often-quoted 70% comes from LinkedIn's 2015 Global Talent Trends survey of 20,931 members. A more recent U.S. reading is Gallup's: in late 2025, 11% of employees were actively looking, 40% were watching for opportunities, and the rest were not looking.

#### How do you reach passive candidates on LinkedIn?

Through the channel your relationship allows: a message if you are connected, a connection request – with a specific note – if you are not, or InMail on a paid plan. Lead with one true detail about the person and one real detail about the role, and ask for something small.

#### How many times should you follow up with a passive candidate?

A sensible starting point to test is a first message once they accept, then two follow-ups about a week apart, stopping as soon as they reply. The published data comes from recruiting email sequences, where replies flatten after three to five messages.

#### Should I use InMail or a connection request?

A connection request costs nothing and keeps the conversation in your network, but a free account can add a note to only three requests a month. InMail reaches people outside your network on a paid plan, and the credit comes back when they accept, decline or reply within 90 days. Our [InMail guide](/guides/linkedin-inmail) has the credits per plan.

#### Can AI write recruiting outreach messages?

Yes, if it works from facts you supply and a recruiter approves each draft. LinkedIn's own AI-Assisted Messages in Recruiter makes the recruiter responsible for reviewing every draft, and the same rule belongs in any agent or script you build.

## Build it in, or hand it to an agent

Build the research, draft, review and send loop into your ATS, CRM or recruiting tool with the REST API, the [Node and Python SDKs](/sdks/installation) or the shell [CLI](/cli/getting-started). Or have an AI agent run it out of the box through the [MCP server](/mcp/overview), the agent-friendly CLI or a ready-made [skill](/skills) – researching each candidate, drafting against your role brief and sending only what you approve, on your own LinkedIn account. Plans are flat per seat, from $49/mo billed annually – see [pricing](/pricing).

*Facts verified November 2, 2026 – LinkedIn Help pages, LinkedIn's published InMail data, Gallup and the vendor pages named here checked on that date.*
