FlowKit

Automating LinkedIn Ads reporting with n8n and AI

By Clément Lacaille (Tech-Bharat) · Published 3 September 2026 · 6 min read · how we build and test

Complete FlowKit Bundle — €269

12 ready-to-import n8n workflows, setup guide in French, 14-day guarantee

See the bundle

Unlike Google Ads or Meta Ads, LinkedIn Ads has no native reporting node in n8n — yet for a lot of B2B teams, it's the ad platform with the highest cost per lead, and therefore the one that most deserves rigorous tracking. This guide covers getting access to LinkedIn's Marketing API, querying the adAnalytics endpoint from n8n via HTTP Request, and delivering an AI cost-per-lead summary straight to Slack or email.

Why n8n has no native node for LinkedIn Ads reports

n8n's built-in LinkedIn node covers organic publishing — creating a post on a profile or company page (see our guide on automating LinkedIn posts with AI) — plus syncing lead form responses via webhook. It doesn't cover the advertising side: campaigns, budgets, and performance metrics live under a separate API, the Marketing API (Advertising API), which has no dedicated node in n8n. The only available route is the HTTP Request node, configured to query LinkedIn's REST endpoints directly.

Getting access to the LinkedIn Ads API

The first structural difference from Google Ads or Meta, whose read-only reporting access is open to any developer: LinkedIn gates the r_ads and r_ads_reporting scopes behind a review. In the LinkedIn Developer Portal, you need to create an app, attach the Advertising API product to it (under Marketing Developer Platform), and fill out an access request form. The stated turnaround is 3 to 10 business days, with near-automatic approval for legitimate marketing or agency use — but that delay needs to be built into the project timeline, not discovered while wiring up n8n.

Once access is granted, authentication follows a standard OAuth2 flow (Authorization Code): create a generic OAuth2 API credential in n8n with the Client ID and Client Secret from the LinkedIn app, the authorization URL https://www.linkedin.com/oauth/v2/authorization and the token URL https://www.linkedin.com/oauth/v2/accessToken, requesting the r_ads and r_ads_reporting scopes.

Querying the adAnalytics API from n8n

The core endpoint is GET https://api.linkedin.com/rest/adAnalytics. Two headers are mandatory on every call, alongside the OAuth2 token:

  • LinkedIn-Version: 202508 (or the current monthly version) — LinkedIn ships a new version every month in YYYYMM format, each supported for at least a year; omitting it exposes you to a default behavior with no guarantees.
  • X-Restli-Protocol-Version: 2.0.0 — required by the Rest.li protocol the API is built on.

The request uses a q parameter (finder) that determines the shape of the result: q=analytics for grouping by a single element (e.g. by campaign), q=statistics for crossing up to three dimensions. pivot=CAMPAIGN breaks metrics down by campaign, and campaigns[0]=urn:li:sponsoredCampaign:123456789 filters on the campaigns you want by their URN — not their bare numeric ID, a common trap for anyone coming from Google Ads or Meta, where the raw ID is enough. The date range uses a nested syntax specific to Rest.li rather than a simple start_date/end_date:

dateRange=(start:(day:1,month:8,year:2026),end:(day:31,month:8,year:2026))

A gotcha worth knowing: the Rest.li protocol expects the parentheses, colons, and commas in this syntax to stay exactly as-is in the URL, without percent-encoding. If you build this query through the HTTP Request node's Query Parameters tab, n8n automatically encodes those characters and LinkedIn rejects the call. The reliable fix is to build the full URL, query string included, as an expression directly in the URL field itself (bypassing the Query Parameters tab), so the string goes out without extra re-encoding.

Adapting metrics for B2B reporting

The fields parameter determines which metrics come back: impressions, clicks, costInLocalCurrency, but also two LinkedIn-specific fields that often matter more than raw clicks in B2B — oneClickLeads (leads captured through native Lead Gen Forms, without leaving LinkedIn) and externalWebsiteConversions (conversions tracked on your site, worth pairing with our guide on the LinkedIn Conversions API if you're already sending those events server-side). A Code node then computes cost per lead — the metric that actually matters in B2B, more so than the generic CPA used in e-commerce:

return items.map(item => {
  const spend = Number(item.json.costInLocalCurrency);
  const leads = Number(item.json.oneClickLeads ?? 0) + Number(item.json.externalWebsiteConversions ?? 0);
  return {
    json: {
      platform: "linkedin_ads",
      campaignUrn: item.json.pivotValues?.[0],
      spend,
      clicks: Number(item.json.clicks),
      leads,
      costPerLead: leads > 0 ? spend / leads : null,
    }
  };
});

Comparing LinkedIn Ads to Google Ads and Meta Ads

If you're already tracking Google Ads and Meta in a consolidated report (see our guide on automatic Google Ads and Meta Ads reporting), the same normalization principle applies here: a common schema with platform, spend, clicks, conversions lets you sort every platform together by rising cost per acquisition. The nuance to keep in mind: LinkedIn's cost per lead is structurally higher than Google's or Meta's for most B2B sectors — comparing the three platforms on raw CPA without accounting for the quality of captured leads (often higher on LinkedIn, thanks to professional targeting) skews the reading. A study published in Economics of Development by Oklander, Karandin, Ptashchenko and Dybach (2025), on LinkedIn's use as a targeted advertising tool in industrial B2B marketing, confirms that the platform's return on investment depends heavily on the quality of its professional targeting rather than raw click volume — one more reason to track cost per qualified lead rather than the raw click.

Qualifying captured leads before counting them

A lead from a LinkedIn Lead Gen Form isn't worth the same as a visitor qualified through a classic contact form — the oneClickLeads field counts every submission, with no judgment on relevance. Wiring the output of those forms into automated scoring, as described in our guide on AI-based inbound lead qualification, lets you weight the real cost per lead by a qualification rate instead of taking the raw number at face value — a correction that often changes the campaign ranking in the final report entirely.

Generating the AI summary and distributing it

Just like a Google Ads / Meta Ads report, an AI node (see our guide on connecting Claude or GPT to n8n) turns the consolidated table into a short summary: campaigns with the best cost per lead, ones to pause, and a budget-reallocation recommendation — keeping the prompt strictly constrained to the supplied numbers, with no extrapolation on unverifiable causes. The report then goes out on Slack on a weekly cron, with the raw data archived separately to rebuild a multi-month history — the same archiving logic detailed in our article on the Supabase audit trail, applied here to advertising metrics instead of compliance events.

Common pitfalls

  • Discovering the Marketing Developer Platform review delay too late — 3 to 10 business days before you have a working token, which belongs in the project timeline, not its execution.
  • Filtering campaigns by numeric ID instead of their full URN (urn:li:sponsoredCampaign:...) — the adAnalytics API silently rejects or ignores a malformed filter.
  • Letting n8n auto-encode the Rest.li syntax (dateRange=(start:(...)...)) through the HTTP Request node's Query Parameters tab, instead of building the full URL directly in the URL field.
  • Skipping the LinkedIn-Version header — the call still works, but then relies on a default behavior with no guarantee over time.
  • Comparing raw cost per lead across platforms without weighting by actual lead qualification rate — a pricier LinkedIn lead isn't necessarily a less profitable one.

Going further

The principle behind this workflow — authenticated API call, normalization in a Code node, AI-constrained summary, archiving and scheduled distribution — is the same one structuring the reporting workflows in the Compliance & Audit Pack (€149). If you scale this kind of AI summary across multiple ad accounts or several reports a week, our guide on tracking AI call costs in n8n helps keep that expense line under control.

FAQ

Frequently asked questions

Does n8n have a native node for LinkedIn Ads reports?

No. n8n's native LinkedIn node only covers organic post publishing (profile or company page) and syncing lead form responses via webhook. To pull advertising performance metrics (impressions, clicks, cost, leads), you need the HTTP Request node querying LinkedIn's adAnalytics API directly.

Do you need special authorization to access the LinkedIn Ads reporting API?

Yes. Unlike Google Ads or Meta, production access to the r_ads and r_ads_reporting scopes requires adding the 'Advertising API' product to your app in the LinkedIn Developer Portal and passing a review. It typically takes 3 to 10 business days, with near-automatic approval for legitimate marketing or agency use — but that delay needs to be planned for before building the workflow, not discovered while connecting n8n.

Which OAuth2 scopes does this workflow need?

At minimum r_ads (access to ad accounts and campaigns) and r_ads_reporting (access to performance metrics via adAnalytics). Both scopes replaced the older r_ad_campaigns, which existing apps have had automatically migrated.

Why is the LinkedIn-Version header mandatory on every call?

LinkedIn ships a new version of its Marketing API every month, formatted as YYYYMM (e.g. 202508), each supported for at least a year. Without an explicit LinkedIn-Version header, LinkedIn falls back to a default behavior that isn't guaranteed and can be deprecated — setting it explicitly prevents a silent behavior change from breaking the workflow months later.

Complete FlowKit Bundle

€269