Skip to content

LinkedIn

Overview#

The LinkedIn integration connects your Cognest assistant to the LinkedIn Marketing and Community Management APIs. Publish posts, share articles, manage company pages, monitor engagement, and respond to messages programmatically. Cognest handles the OAuth 2.0 three-legged flow, token refresh, and rate limiting transparently.

Prerequisites#

  1. Create an app in the LinkedIn Developer Portal.
  2. Request the Share on LinkedIn and Sign In with LinkedIn using OpenID Connect products for your app.
  3. If managing a company page, request the Community Management API product and ensure the authenticated user is a Super Admin of the page.
  4. Copy your Client ID and Client Secret from the Auth tab of your LinkedIn app.
  5. Add the redirect URI http://localhost:3000/auth/linkedin/callback to your app's OAuth 2.0 settings.
.env
LINKEDIN_CLIENT_ID=your_client_id
LINKEDIN_CLIENT_SECRET=your_client_secret

OAuth 2.0 Flow

LinkedIn uses OAuth 2.0 with authorization code grant. Cognest will prompt you to complete the browser-based authorization on first use. Tokens are stored encrypted and refreshed automatically before expiry.

Configuration#

Add the LinkedIn integration to your cognest.config.yaml:

cognest.config.yaml
integrations:
  linkedin:
    enabled: true
    credentials:
      client_id: ${LINKEDIN_CLIENT_ID}
      client_secret: ${LINKEDIN_CLIENT_SECRET}
    settings:
      # OAuth redirect URI (must match your LinkedIn app settings)
      redirect_uri: http://localhost:3000/auth/linkedin/callback
      # Scopes to request during authorization
      scopes:
        - openid
        - profile
        - email
        - w_member_social
      # Company page URN for organization-level posting (optional)
      company_urn: "urn:li:organization:12345678"
      # Poll interval for engagement and message checks (seconds)
      poll_interval: 60

SDK Usage#

index.ts
import { Cognest } from '@cognest/sdk'

const cognest = new Cognest()
const linkedin = cognest.integration('linkedin')

// Post to your personal profile
await linkedin.createPost({
  text: 'Excited to share our latest product update!',
  visibility: 'PUBLIC',
})

await cognest.start()

Available Methods#

MethodParametersDescription
createPost(options){ text, visibility?, mediaUrls?, companyUrn? }Publish a text or media post. Defaults to the authenticated user's profile; pass companyUrn to post as a company page.
shareArticle(options){ url, title?, description?, companyUrn? }Share an article link with optional title and description.
getProfile(memberId?)memberId?: stringRetrieve a LinkedIn profile. Defaults to the authenticated user.
getCompanyPage(urn)urn: stringFetch company page details including follower count, description, and admin list.
getConnections(options?)options?: { start?, count? }List connections of the authenticated user with pagination support.
sendMessage(options){ recipientUrn, text, subject? }Send a LinkedIn message to a 1st-degree connection.

Events#

LinkedIn events are delivered via polling since the API does not support webhooks for most resources. Configure poll_interval in settings to control check frequency.

EventPayloadDescription
post:engagement{ postUrn, type, actorUrn, actorName, createdAt }Fired when someone likes, comments on, or shares one of your posts. The type field is 'like', 'comment', or 'share'.
message:received{ senderUrn, senderName, text, threadId, createdAt }Fired when a new message is received in LinkedIn messaging.
connection:new{ memberUrn, memberName, connectedAt }Fired when a new connection request is accepted.
events.ts
linkedin.on('post:engagement', async (event) => {
  if (event.type === 'comment') {
    console.log(`${event.actorName} commented on your post`)
  }
})

linkedin.on('message:received', async (event) => {
  console.log(`Message from ${event.senderName}: ${event.text}`)
})

linkedin.on('connection:new', async (event) => {
  // Send a welcome message to new connections
  await linkedin.sendMessage({
    recipientUrn: event.memberUrn,
    text: `Hi ${event.memberName}, thanks for connecting! Happy to be in your network.`,
  })
})

Example#

A complete example that automates thought-leadership posting and engagement monitoring for a company page:

bot.ts
import { Cognest } from '@cognest/sdk'

const cognest = new Cognest()
const linkedin = cognest.integration('linkedin')

const COMPANY_URN = 'urn:li:organization:12345678'

// Schedule daily thought-leadership posts
cognest.skill('daily-linkedin-post', {
  schedule: '0 9 * * 1-5', // 9 AM, weekdays
  handler: async () => {
    // Generate a post using the AI engine
    const post = await cognest.engine.run({
      prompt: `Write a concise LinkedIn post (under 1300 characters) for a B2B SaaS company
that sells AI-powered workflow automation. The tone should be professional but
approachable. Include 2-3 relevant hashtags at the end. Topic: pick a trending
theme in AI automation this week.`,
    })

    await linkedin.createPost({
      text: post.text,
      visibility: 'PUBLIC',
      companyUrn: COMPANY_URN,
    })

    console.log('Daily LinkedIn post published')
  },
})

// Monitor engagement and auto-respond to comments
linkedin.on('post:engagement', async (event) => {
  if (event.type !== 'comment') return

  // Fetch the comment content using the API
  const profile = await linkedin.getProfile()

  console.log(`Engagement on post ${event.postUrn}: ${event.type} by ${event.actorName}`)
})

// Auto-welcome new connections with a personalized message
linkedin.on('connection:new', async (event) => {
  const profile = await linkedin.getProfile(event.memberUrn)

  const message = await cognest.engine.run({
    prompt: `Write a short, professional LinkedIn welcome message (2-3 sentences)
for a new connection named ${event.memberName}. Mention that we'd love to
learn about their work and explore potential collaboration.`,
  })

  await linkedin.sendMessage({
    recipientUrn: event.memberUrn,
    text: message.text,
  })

  console.log(`Welcome message sent to ${event.memberName}`)
})

// Weekly content share: find and share relevant industry articles
cognest.skill('weekly-article-share', {
  schedule: '0 14 * * 3', // 2 PM on Wednesdays
  handler: async () => {
    const article = await cognest.engine.run({
      prompt: `Suggest one recent high-quality article URL about AI in enterprise
workflows. Return JSON: { "url": "...", "title": "...", "commentary": "..." }
where commentary is a 2-sentence take on the article.`,
      responseFormat: 'json',
    })

    const { url, title, commentary } = JSON.parse(article.text)

    await linkedin.shareArticle({
      url,
      title,
      description: commentary,
      companyUrn: COMPANY_URN,
    })

    console.log(`Shared article: ${title}`)
  },
})

await cognest.start()
console.log('LinkedIn automation is running...')

Troubleshooting#

Common Issues

401 Unauthorized: Your OAuth tokens may have expired. LinkedIn access tokens expire after 60 days (or 365 days for refresh tokens). Cognest handles automatic refresh, but if the refresh token itself has expired, you will need to re-authorize through the OAuth flow. 403 Restricted: Posting to a company page requires the authenticated user to be a Super Admin of that page. Verify your admin status in the company page settings on LinkedIn. "Scope not authorized" error: Ensure your LinkedIn app has been approved for the required products (Share on LinkedIn, Community Management API). Product approval can take 1-5 business days. Rate limiting: LinkedIn allows approximately 100 API calls per day per user and 1,000 per day per app. Use poll_interval of 60 seconds or higher to avoid hitting limits.

Testing with a Test Company Page

LinkedIn provides a test company page for development. Use the "Test" toggle in your Developer Portal app settings to create posts that are only visible to app admins, avoiding any impact on your live company page during development.