# LinkedIn Social Listening: Monitor Mentions and Competitors with AI

How to do LinkedIn social listening – track brand mentions, competitors and topic conversations with a weekly AI-agent digest on your own account.

What people say about your brand, your competitors and your category on LinkedIn is useful – if you can see it without reading the feed all day.

> **The short version.** LinkedIn social listening means watching three things: posts that mention your company, what your competitors and their people publish, and the conversations in your category. LinkedIn's own tools cover a slice – your Page sees posts that tag it, and Page competitor analytics compares you with one competitor on a free Page or up to nine on Premium. Beyond that, the data comes by one of three routes: official-API Page connectors (your own Page and its comments), public-web keyword samples that monitoring tools collect, or LinkedIn's own post search run from a logged-in account. The last route is what an AI agent can run on your account every week, turning keyword searches into a digest of themes, objections and who is engaging. Every route is a sample, not every post on LinkedIn.

## What LinkedIn social listening covers – and what it can't see

Listening on LinkedIn has three jobs:

- **Your brand** – who mentions your company, tagged or not.
- **Your competitors** – what their Pages publish, and what their people post.
- **Your category** – what buyers and peers say about the problem you solve.

The data reaches you by different routes, and a product may use more than one:

| Route | What it sees | Limits |
|---|---|---|
| LinkedIn's native Page tools | Posts that @-tag your Page, under the Page's Activity tab ([LinkedIn Help](https://www.linkedin.com/help/linkedin/answer/a567278)). Competitor analytics for 1 competitor on a free Page or up to 9 on Premium – followers, organic content metrics, trending competitor posts from the last 30 days ([LinkedIn Help](https://www.linkedin.com/help/linkedin/answer/a789847)) | Untagged mentions; people rather than Pages |
| Official-API Page connectors | Your own Business Page's posts, comments and insights, inside a listening suite. Mentionlytics, for example, notes that commenters come through anonymized | Not a keyword search across LinkedIn |
| Public-web keyword samples | Public LinkedIn posts with your keywords that appear on the web – the keyword monitoring some suites offer, such as Mentionlytics and Brand24 | A sample; Mentionlytics states it cannot retrieve every public post with your keywords |
| LinkedIn post search from a logged-in account | The posts LinkedIn's own content search returns for your keyword, as that account sees them – what an agent on your account runs | Each search needs a keyword; results are bounded per call; LinkedIn widens narrow queries; no private content |

Whichever route you use, treat the result as a sample. It tells you what is being said and by whom, not how many times your brand came up across all of LinkedIn.

## Native tools, listening suites, keyword monitors or your own agent

| Option | Best for | Watch out for |
|---|---|---|
| LinkedIn Page analytics | A free baseline for your own Page: tagged mentions and a competitor comparison | Competitor tracking depends on your Page tier; untagged mentions do not show |
| Listening suites (Sprout, Brand24, Mentionlytics) | Reporting across several social networks in one dashboard | On LinkedIn they combine Page connectors with public-web keyword samples, depending on the product |
| LinkedIn keyword monitors (Octolens, OutX, Buska) | Ready-made alerts on keywords, people and companies | Their coverage and sources vary; OutX is also listed as an MCP server for AI agents |
| An agent or script on your own account (Linked API) | A custom weekly digest with your own searches, LLM analysis and routing into your tools | You run and schedule it; it sees what your account's search returns |

Agent access is not unique to any one route. What an agent on your own account adds is control: you choose the searches, the digest format and where the results go.

## The weekly listening digest: what to watch

Four watches, each one search. "Past week" and "latest" keep each run to new posts.

| Watch | What to search | Linked API call | Caveat |
|---|---|---|---|
| **Brand mentions** (baseline, untagged included) | Your brand name as the keyword | `searchPosts` with `term: "<brand>"`, `sort: latest`, `datePosted: pastWeek` – then keep only posts whose text contains the brand | LinkedIn widens narrow queries, so check each hit |
| **Tagged mentions** (optional) | The same keyword, limited to posts that tag your company | The same search plus `mentioningCompanies: ["<brand>"]` | This filter is a company-mention facet combined with the keyword, so it narrows to tagged posts. Never use it as the only brand watch |
| **Competitors' Pages** | What each competitor publishes | `fetchCompany` with `retrievePosts` and `postsRetrievalConfig: { limit, since }` | Page posts only |
| **Competitors' people** | What their employees post about your category | `searchPosts` with your category keyword plus `authorCompanies: ["<competitor>"]` | Matches the author's current company as LinkedIn shows it |
| **Category conversations** | Posts about the problem you solve | `searchPosts` with a problem phrase, past week, latest | Pick phrases buyers use, not your product's vocabulary |

Then, for the few hits worth it, see **who engages**: `fetchPost` with `retrieveComments` and `retrieveReactions`. Comments carry LinkedIn's relative time, such as `3d`; reactions carry no time.

Company and person filters accept a name, or a name with an identifier that pins the exact company. If LinkedIn's filter panel does not offer a match for the name, the search fails with `filterNotApplied` rather than returning unfiltered results. Details are in the [post search reference](/docs/action-st-search-posts).

## Run it with an AI agent

The digest runs from a plain-language instruction. Give an assistant such as Claude access to your account through the [MCP server](/mcp/available-tools) – tools `search_posts`, `fetch_company` and `fetch_post` – the agent-friendly [CLI](/cli/posts), or a ready-made [skill](/skills). Setup is covered in [giving an AI agent access to LinkedIn](/guides/linkedin-ai-agent).

A runnable instruction. It is a starting point, not a record of an observed run:

```text
Run my weekly LinkedIn listening digest for the past week.

Brand: "Acme Analytics". Competitors: "Example Rival", "Other Rival".
Category phrase: "pipeline forecasting".

1. Search posts for "Acme Analytics" (latest, past week). Keep only posts whose text
   actually mentions Acme Analytics. Do not use the mentioning-company filter for this.
2. Fetch each competitor's company page with its posts from the last 7 days.
3. Search posts for "pipeline forecasting" from people who work at each competitor.
4. Search posts for "pipeline forecasting" (latest, past week).
5. For the three most-engaged hits, fetch the comments.

Write the digest in this format:
- Themes: 3–5 recurring themes, each with 1–2 post links.
- Objections and questions people raised, with links.
- Competitors: what each one published and what got engagement.
- Notable authors and commenters worth following.
- Share of the observed sample by watch (counts of the posts you kept, not LinkedIn-wide).
- Items for sales: posts from people asking about the problem we solve.
```

From the terminal, the same searches look like this:

```bash
linkedin post search --term "Acme Analytics" --sort latest --date-posted pastWeek --json
linkedin post search --term "pipeline forecasting" --author-companies "Example Rival" --date-posted pastWeek --json
```

Use `--mentioning-companies` only for a separate tagged-mentions watch. Scheduling is yours: a weekly agent session, cron, n8n or Make.

## Or schedule it in code

The same digest as a script. It runs the watches and writes the new posts to `digest-input.json` for whichever LLM you use for the summary. Posts already sent in an earlier week are skipped.

```typescript
import LinkedApi, { type TSearchPostsParams } from '@linkedapi/node';
import { existsSync, readFileSync, writeFileSync } from 'node:fs';

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

const BRAND = 'Acme Analytics';
const COMPETITORS = [{ name: 'Example Rival', pageUrl: 'https://www.linkedin.com/company/example-rival' }];
const CATEGORY_TERM = 'pipeline forecasting';
const SEEN_FILE = 'listening-seen.json';
const OUTPUT_FILE = 'digest-input.json';
const ONE_WEEK_MS = 7 * 24 * 60 * 60 * 1000;
const PAST_WEEK = { sort: 'latest', datePosted: 'pastWeek' } as const;

interface THit {
  watch: string;
  url: string;
  author: string | null;
  time: string;
  text: string;
  reactions: number;
  comments: number;
}

async function searchWatch(watch: string, params: TSearchPostsParams): Promise<Array<THit>> {
  const workflow = await linkedapi.searchPosts.execute({ limit: 50, ...params });
  const { data, errors } = await linkedapi.searchPosts.result(workflow.workflowId);
  if (errors.length > 0) console.warn(watch, errors.map((error) => error.type));
  return (data ?? []).map((post) => ({
    watch,
    url: post.url,
    author: post.author?.name ?? null,
    time: post.time,
    text: post.text ?? '',
    reactions: post.reactionsCount,
    comments: post.commentsCount,
  }));
}

async function competitorPagePosts(competitor: { name: string; pageUrl: string }): Promise<Array<THit>> {
  const workflow = await linkedapi.fetchCompany.execute({
    companyUrl: competitor.pageUrl,
    retrievePosts: true,
    postsRetrievalConfig: { limit: 20, since: new Date(Date.now() - ONE_WEEK_MS).toISOString() },
  });
  const { data, errors } = await linkedapi.fetchCompany.result(workflow.workflowId);
  if (errors.length > 0) console.warn(competitor.name, errors.map((error) => error.type));
  return (data?.posts ?? []).map((post) => ({
    watch: `competitor page: ${competitor.name}`,
    url: post.url,
    author: competitor.name,
    time: post.time,
    text: post.text ?? '',
    reactions: post.reactionsCount,
    comments: post.commentsCount,
  }));
}

async function collectDigestInput() {
  const seen = new Set<string>(existsSync(SEEN_FILE) ? JSON.parse(readFileSync(SEEN_FILE, 'utf8')) : []);

  const brandHits = await searchWatch('brand', { term: BRAND, filter: PAST_WEEK });
  const hits = brandHits.filter((hit) => hit.text.toLowerCase().includes(BRAND.toLowerCase()));

  for (const competitor of COMPETITORS) {
    hits.push(...(await competitorPagePosts(competitor)));
    hits.push(...(await searchWatch(`competitor people: ${competitor.name}`, {
      term: CATEGORY_TERM,
      filter: { ...PAST_WEEK, authorCompanies: [competitor.name] },
    })));
  }
  hits.push(...(await searchWatch('category', { term: CATEGORY_TERM, filter: PAST_WEEK })));

  const fresh = hits.filter((hit) => !seen.has(hit.url));
  const excerpts = fresh.map((hit) => ({ ...hit, text: hit.text.slice(0, 500) }));
  writeFileSync(OUTPUT_FILE, JSON.stringify(excerpts, null, 2));
  writeFileSync(SEEN_FILE, JSON.stringify([...seen, ...fresh.map((hit) => hit.url)]));
}

collectDigestInput();
```

```python
import json
import os
from datetime import datetime, timedelta, timezone

from linkedapi import FetchCompanyParams, LinkedApi, LinkedApiConfig, SearchPostsParams

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

BRAND = "Acme Analytics"
COMPETITORS = [{"name": "Example Rival", "page_url": "https://www.linkedin.com/company/example-rival"}]
CATEGORY_TERM = "pipeline forecasting"
SEEN_FILE = "listening-seen.json"
OUTPUT_FILE = "digest-input.json"
PAST_WEEK = {"sort": "latest", "date_posted": "pastWeek"}


def to_hit(watch, post, author):
    return {
        "watch": watch,
        "url": post.url,
        "author": author,
        "time": post.time,
        "text": post.text or "",
        "reactions": post.reactions_count,
        "comments": post.comments_count,
    }


def search_watch(watch, term, filter_):
    workflow = linkedapi.search_posts.execute(SearchPostsParams(term=term, filter=filter_, limit=50))
    result = linkedapi.search_posts.result(workflow.workflow_id)
    if result.errors:
        print(watch, [error.type for error in result.errors])
    return [to_hit(watch, post, post.author.name if post.author else None) for post in result.data or []]


def competitor_page_posts(competitor):
    since = (datetime.now(timezone.utc) - timedelta(days=7)).strftime("%Y-%m-%dT%H:%M:%SZ")
    workflow = linkedapi.fetch_company.execute(
        FetchCompanyParams(
            company_url=competitor["page_url"],
            retrieve_posts=True,
            posts_retrieval_config={"limit": 20, "since": since},
        )
    )
    result = linkedapi.fetch_company.result(workflow.workflow_id)
    if result.errors:
        print(competitor["name"], [error.type for error in result.errors])
    posts = result.data.posts if result.data else None
    return [to_hit(f"competitor page: {competitor['name']}", post, competitor["name"]) for post in posts or []]


def collect_digest_input():
    seen = set()
    if os.path.exists(SEEN_FILE):
        with open(SEEN_FILE) as f:
            seen = set(json.load(f))

    brand_hits = search_watch("brand", BRAND, PAST_WEEK)
    hits = [hit for hit in brand_hits if BRAND.lower() in hit["text"].lower()]

    for competitor in COMPETITORS:
        hits += competitor_page_posts(competitor)
        hits += search_watch(
            f"competitor people: {competitor['name']}",
            CATEGORY_TERM,
            {**PAST_WEEK, "author_companies": [competitor["name"]]},
        )
    hits += search_watch("category", CATEGORY_TERM, PAST_WEEK)

    fresh = [hit for hit in hits if hit["url"] not in seen]
    excerpts = [{**hit, "text": hit["text"][:500]} for hit in fresh]
    with open(OUTPUT_FILE, "w") as f:
        json.dump(excerpts, f, indent=2)
    with open(SEEN_FILE, "w") as f:
        json.dump(sorted(seen | {hit["url"] for hit in fresh}), f)


collect_digest_input()
```

Every call is asynchronous – `execute` starts the work and returns a workflow ID, `result` waits for it – and action failures come back in `errors`, not as exceptions. A failed watch is logged and the rest of the digest still runs. Feed `digest-input.json` to your model with the same digest format as the agent instruction above. To pin a competitor exactly, pass `{ name, id }` with its company URN or numeric ID instead of the bare name.

## Turning the digest into decisions

A digest is only worth the time if someone acts on it:

- **Themes** feed your content plan – what your category argues about this week.
- **Objections and questions** go to sales enablement and to the FAQ on your site.
- **Competitors' launches and messaging** shape your counter-positioning before your buyers ask about them.
- **People asking about the problem you solve** are sales-relevant; route them the way [LinkedIn buying signals](/guides/linkedin-buying-signals) describes, with a person reviewing before any outreach.

Report shares as the share of your observed sample – "most of the competitor posts we saw were about pricing" – never as LinkedIn-wide share of voice.

## Limits and guardrails

- **A sample, not a firehose.** You see what your account's search returns, bounded per call.
- **A keyword is required.** Every post search needs a term, and LinkedIn widens narrow queries, so check each hit.
- **No private content,** and no posts the search does not surface.
- **No streaming or alerts.** You schedule the run; Linked API has no post-mention webhook.
- **The analysis is the LLM's,** not LinkedIn's. Themes and sentiment are interpretations – keep the post links next to every claim.
- **Pace and limits.** Searches count toward per-action limits by category and period, which you can see and set with the [limits API](/docs/admin-limits). The account runs in a dedicated cloud browser at a human pace.

Need the post data itself – full text, engagers, a CSV – rather than a digest? That is the job of the [LinkedIn post scraper guide](/guides/linkedin-post-scraper#search-linkedin-posts-by-keyword).

## Frequently Asked Questions (FAQ)

#### What is LinkedIn social listening?

Watching what is said on LinkedIn about your brand, your competitors and your category, then turning it into decisions – content, positioning, sales enablement.

#### Can you see who mentions your company on LinkedIn?

Posts that tag your Page show in the Page's Activity tab. Untagged mentions only appear through keyword search – a monitoring tool's public-web sample, or LinkedIn's own post search run from an account.

#### How do I monitor competitors on LinkedIn?

Start with Page competitor analytics – one competitor on a free Page, up to nine on Premium. For more, collect their Page posts and their employees' posts each week by search, as in the digest above.

#### Is there a LinkedIn social listening API?

LinkedIn's official APIs centre on your own Page's content, and access to them is gated – see [LinkedIn API access](/guides/linkedin-api-access). Linked API runs LinkedIn's post search and company pages on your own account, so a script or an agent can collect the digest.

#### Do I need a social listening tool for LinkedIn?

It depends on the job. A suite fits multi-network reporting, a keyword monitor fits ready-made alerts, and an agent on your own account fits a custom digest that feeds your own tools.

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

Build the digest into your own tools with the REST API, the [Node and Python SDKs](/sdks) or the [CLI](/cli). Or have an AI agent run it out of the box through the [MCP server](/mcp/available-tools), the agent-friendly CLI or a ready-made [skill](/skills). Plans start at $49 a seat a month billed annually – see [pricing](/pricing).

*Facts verified October 9, 2026 – LinkedIn Page mentions and competitor analytics against LinkedIn Help; Mentionlytics' LinkedIn monitoring routes against its help center; Brand24, Octolens, OutX and Buska descriptions against their live pages on that date.*
