LinkedIn automation done properly means using LinkedIn’s official API to publish posts you have approved, not bots that click around the site. This guide builds that with n8n and OpenAI: a workflow that drafts a LinkedIn post from a topic, sends it to you for approval, and publishes it through LinkedIn’s Posts API. It works for personal profile posts out of the box; posting as a company page needs extra approval from LinkedIn, covered below.
Updated October 2026: I rewrote this guide. The earlier version said the n8n LinkedIn node was broken and told you to edit files inside node_modules to patch it. That advice is obsolete and risky: the node’s API-version problem has been fixed in n8n itself, and the real cause (LinkedIn retires old API versions) is explained below. It also quoted a “10 posts per day” limit that LinkedIn doesn’t publish, and its code samples were pseudo-configuration, not importable n8n JSON. Everything here is based on LinkedIn’s and n8n’s current documentation.
Two ground rules first. LinkedIn’s User Agreement (section 8.2, “Don’ts”) prohibits using “bots or other unauthorized automated methods” to access the service or to “create, comment on, like, share, or re-share posts,” and bans scraping. Publishing through LinkedIn’s official, approved API with your own authenticated app is the sanctioned route; browser bots, scrapers and unofficial tools that mass-post or auto-engage are not, and can get your account restricted. Second, AI-written posts that nobody reviews tend to read as generic and get little engagement, which is why this workflow keeps a human approval step.
Prerequisites
- An n8n instance (version 2.x, kept up to date; see the version note below). If you don’t have one, see our guide to deploying n8n on Google Cloud.
- An OpenAI API key with credit on the account, added in n8n under Credentials.
- A LinkedIn account and a LinkedIn Company Page. LinkedIn requires a developer app to be associated with a Company Page, even if you only plan to post to your personal profile.
- A LinkedIn developer app with the right products enabled (next section).
What LinkedIn lets you do, and what needs approval
The two permissions that matter for posting, from LinkedIn’s Posts API documentation:
| Permission | Lets you | Access |
|---|---|---|
w_member_social | Post, comment and like on behalf of the authenticated member (your personal profile) | Granted through the self-serve “Share on LinkedIn” product |
w_organization_social | Post on behalf of a company page, restricted to members with an admin or content-admin role on that page | Requires LinkedIn’s Community Management API access and app review, which is not guaranteed |
So the realistic split is: personal-profile posting is self-serve; company-page posting means applying to LinkedIn and waiting for approval. Build and test with your personal profile first.
Rate limits: LinkedIn does not publish standard limits in its documentation. Limits are per application and per member, reset daily at midnight UTC, and exceeding them returns HTTP 429. You can see the actual limits for each endpoint your app uses in the Developer Portal: open your app and go to its Analytics tab (it lists endpoints you have called at least once that day). Plan around those numbers instead of any figure quoted in a blog post, including older versions of this one.
Step 1: Create the LinkedIn App and n8n Credential
n8n’s LinkedIn credentials documentation offers two methods: Community Management OAuth2 for new LinkedIn apps (use this one), and OAuth2 for older apps and accounts. The setup:
- Go to the LinkedIn developer portal and create an app. Give it a name like “n8n integration”, select your Company Page, add a logo and accept the legal agreement.
- In the app’s Products tab, request Share on LinkedIn and Sign In with LinkedIn using OpenID Connect. Both are what the n8n node needs. (Posting as an organization additionally requires the Community Management API and LinkedIn’s app review.)
- Open the Auth tab and copy the Client ID and Primary Client Secret.
- In n8n, create a LinkedIn Community Management OAuth2 API credential, paste both values, add the OAuth redirect URL that n8n shows you to the Authorized redirect URLs in the LinkedIn app, and click Connect to authorize.
n8n encrypts stored credentials, so keep keys there rather than in workflow parameters, and rotate the client secret if you ever suspect a leak.
The “NONEXISTENT_VERSION” error, explained
If you search for LinkedIn problems in n8n you will find reports of a NONEXISTENT_VERSION error. The cause is simple. LinkedIn’s versioned API requires every request to carry a Linkedin-Version header in YYYYMM format (no unversioned calls are allowed), and LinkedIn supports each version for a minimum of one year before retiring it. A request that uses a retired version is rejected. n8n’s LinkedIn node sends a fixed version header, which n8n’s maintainers bump periodically (the node’s source shows fixes in April 2025 and April 2026, the latter setting version 202604). An outdated n8n installation keeps sending an expired version and fails.
The fix is to update n8n, not to patch files inside node_modules. Treat “update n8n at least a few times a year” as part of owning a LinkedIn integration. If you ever hit the error on a current n8n, or need an endpoint the node doesn’t support, you can call the API yourself with an HTTP Request node, as shown later.
Step 2: Build the Workflow
The workflow has five stages: topic in, draft generated, you approve, post published, result logged.
Trigger (Manual / Schedule / Form)
-> Basic LLM Chain + OpenAI Chat Model (draft the post)
-> Send and wait for response (you approve or reject)
-> IF approved
-> LinkedIn: Create Post (publish)
-> log / notify success
else -> stop or ask for a revision
1. Trigger with a topic
Start with a Manual Trigger while building. For regular use, a Form Trigger (you type a topic into a web form) or a Schedule Trigger that reads topics from a Google Sheet or Notion database both work. The trigger needs to output a field such as topic.
2. Draft the post with OpenAI
Add a Basic LLM Chain node with an OpenAI Chat Model attached (pick a current model your account offers; a mid-tier model is plenty for short posts, and model names change too often to hard-code here). Set the prompt to Write a LinkedIn post about: {{ $json.topic }} and, in the chain’s Chat Messages option, add a System message like:
You write LinkedIn posts for [your name/company]. Voice: practical, specific, first-person,
no hype. Structure: a one-line hook, 3-5 short paragraphs or bullets, one concrete takeaway,
and a question to invite replies. Maximum 1,300 characters. At most 3 hashtags at the end.
Never invent statistics, quotes or customer names. If you lack a fact, leave it out.
Give it real material to work from (notes, a changelog, a blog post’s key points) in the prompt; models write far better from specifics than from a bare topic. Set a moderate temperature (around 0.5 to 0.7) for variety. The draft comes back in the chain’s text output field (check the output panel in your version).
Length: a LinkedIn post can be up to 3,000 characters, but shorter posts that fit above the “see more” fold usually perform better. The Posts API will reject over-length commentary with a FIELD_LENGTH_TOO_LONG error, so check the length before posting (see validation below).
3. Human approval
Add an approval step before anything is published. n8n’s Send and Wait for Response operation (available on nodes such as Slack and Gmail) pauses the workflow, sends you the draft with Approve/Decline buttons, and resumes when you answer. (n8n’s Slack approvals documentation shows the flow.) You can also use a Wait node set to resume on a webhook call or form submission. Then an If node routes approved drafts onward and stops the rest.
This step is the single most valuable part of the workflow: it catches wrong facts, off-brand tone and anything that would embarrass you, and it keeps you on the right side of LinkedIn’s rules about authentic engagement.
4. Validate the content
Before posting, add a small Code node (this was called a “Function” node in older n8n) that checks the draft is usable:
const text = ($input.first().json.text ?? "").trim();
if (text.length === 0) throw new Error("Empty post");
if (text.length > 3000) throw new Error("Post exceeds LinkedIn's 3,000-character limit");
return [{ json: { ...$input.first().json, text } }];
5. Publish with the LinkedIn node
Add the LinkedIn node with the operation Post: Create:
- Post As: Person to post on your profile (or Organization if your app has been approved for it).
- Person Name or ID: choose yourself from the dropdown (this is why the “Sign In with LinkedIn using OpenID Connect” product is needed). For an organization, enter just the numeric organization ID, for example
03262013, not the fullurn:li:company:...value. - Text: the approved draft, for example
{{ $json.text }}. - Media Category: leave as none for a text post. Use it if you attach an image or article link.
Execute the workflow end to end with a test topic. Check that the post appears on your LinkedIn profile.
Fallback: call the Posts API with an HTTP Request node
If the LinkedIn node doesn’t support what you need (polls, multi-image posts, mentions, scheduling a draft), call the API directly. In an HTTP Request node choose Authentication → Predefined Credential Type → LinkedIn and your credential, then:
- Method and URL:
POST https://api.linkedin.com/rest/posts - Headers:
X-Restli-Protocol-Version: 2.0.0andLinkedin-Version: YYYYMM, using a version LinkedIn currently supports. The latest at the time of writing is202609; look up supported versions in LinkedIn’s versioning documentation and update the value at least once a year. - Body (JSON):
{
"author": "urn:li:person:YOUR_PERSON_ID",
"commentary": "{{ $json.text }}",
"visibility": "PUBLIC",
"distribution": {
"feedDistribution": "MAIN_FEED",
"targetEntities": [],
"thirdPartyDistributionChannels": []
},
"lifecycleState": "PUBLISHED",
"isReshareDisabledByAuthor": false
}
A successful call returns HTTP 201, and the new post’s ID is in the x-restli-id response header (enable the HTTP Request node’s option to include response headers if you need it). For an organization post, set author to urn:li:organization:ORG_ID and make sure your token has w_organization_social. Note that the Posts API doesn’t scrape URLs for you: an article post must supply its own title, description and thumbnail.
Handling Errors
Create a small separate workflow that starts with an Error Trigger and sends you a Slack or email alert, then set it as the Error Workflow in your main workflow’s settings. Common failures and what they mean, from LinkedIn’s Posts API error table:
| Error | Meaning | What to do |
|---|---|---|
401 EMPTY_ACCESS_TOKEN or expired token | Missing or expired OAuth token | Reconnect the credential in n8n. LinkedIn access tokens expire after a limited period, and refresh tokens are not available to every app, so expect to re-authorize periodically |
403 ACCESS_DENIED | Missing scope or page role | Check the product is enabled and the scope (w_member_social or w_organization_social) was granted; for a page you must be an admin or content admin |
400 FIELD_LENGTH_TOO_LONG | Post text too long | Shorten it; add the length check shown above |
NONEXISTENT_VERSION | Retired Linkedin-Version | Update n8n (or the version header in your HTTP Request node) |
429 TOO_MANY_REQUESTS | Daily rate limit hit | Wait for the midnight-UTC reset; reduce volume; check your limits in the Developer Portal Analytics tab |
409 CONFLICT, 500, 503 | Transient LinkedIn-side problem | Retry. Enable Retry On Fail on the node |
For OpenAI rate-limit errors (HTTP 429 from OpenAI), turn on Retry On Fail with a wait between tries on the OpenAI node. If you process a list of topics, use a Loop Over Items node with a Wait node so you don’t send everything at once.
Good Practice and Compliance
- Keep a human in the loop. Approve every post. Don’t build workflows that post, comment, like or message on a schedule with no review; that is exactly the pattern LinkedIn’s rules and spam detection target.
- Post sparingly. One to a few good posts a week beats a daily stream of generic ones, for both reach and account safety.
- Don’t use the API to drive engagement artificially. No automated comments, likes, connection requests or messages, and no pods or fake engagement. The official API doesn’t offer most of these anyway.
- Disclose where appropriate and verify facts. You are responsible for what is published under your name. Check every claim, number and quote in a draft.
- Protect credentials. Keep tokens in n8n credentials, limit who can edit the workflow, and revoke the app’s access in LinkedIn if you stop using it.
- Stay on supported API versions. Update n8n regularly, and if you use the HTTP Request approach, update the
Linkedin-Versionheader at least yearly. - Respect privacy law if your content or any stored data involves other people’s personal information.
Conclusion
A sound LinkedIn automation with n8n is modest by design: an AI draft, a human approval, and a publish through the official API. It saves the blank-page time of drafting while keeping you responsible for what goes out. The things that go wrong are predictable: an outdated n8n sending a retired API version, missing scopes or page roles, tokens that expire, and workflows that post without review. Keep n8n updated, check your limits in the Developer Portal, start with personal-profile posting, and apply for Community Management access only when you really need company-page posting.
Next steps: feed the draft step with real source material (a RAG pipeline over your own notes, see our n8n RAG assistant), or route drafts to a teammate for approval before they go live.
Frequently Asked Questions
Why does the LinkedIn node in n8n fail with NONEXISTENT_VERSION?
LinkedIn requires a Linkedin-Version header on every API call and retires each version after a minimum of one year. n8n’s LinkedIn node sends a fixed version that n8n’s maintainers update periodically, so an out-of-date n8n installation ends up sending a retired version. Update n8n. If you call the API through an HTTP Request node, update the version header yourself.
How many LinkedIn posts can I automate per day?
LinkedIn doesn’t publish a standard number. Limits apply per application and per member, reset at midnight UTC, and vary by endpoint. You can see yours in the LinkedIn Developer Portal under your app’s Analytics tab after making a test call. In any case, posting more than a few times a week is rarely worthwhile, and every post should be human-approved.
What LinkedIn permissions do I need for automated posting?
For your personal profile you need the w_member_social permission, which comes with the self-serve “Share on LinkedIn” product. For a company page you need w_organization_social, which requires access to LinkedIn’s Community Management API and passing its app review, and the authorizing member must be an admin or content admin of the page.
Is it against LinkedIn’s rules to automate posting?
Posting through LinkedIn’s official API with your own approved app is the supported route. LinkedIn’s User Agreement prohibits bots and other unauthorized automated methods (including to create, comment on, like or share posts), scraping, and inauthentic engagement. Keep a human approving each post and stay away from browser bots and unofficial tools.
Can I schedule posts in advance?
Not through a LinkedIn “schedule” feature in the node. The usual approach is to schedule the n8n workflow itself (a Schedule Trigger, or a Wait node set to a specific time) so that the publish call happens at the time you want, after approval.
How do I handle OpenAI rate limits in n8n?
Enable Retry On Fail with a wait between tries on the OpenAI node, and when processing a list of items use Loop Over Items with a Wait node to space out requests. Also check that your OpenAI account has credit, since an empty balance also produces errors.
Can I post images or links?
Yes, but not as plain text. The LinkedIn node has a Media Category option for images and articles. With the Posts API directly, images require uploading the image first to get an image URN, and article posts must provide their own title, description and thumbnail because the API doesn’t scrape the URL.