> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nekt.com/llms.txt
> Use this file to discover all available pages before exploring further.

# LinkedIn as a data source

> Bring organic data from your LinkedIn Organization Page or Member Profile to Nekt.

LinkedIn is the world's largest professional networking platform, connecting professionals and businesses globally. The LinkedIn Community Management API provides access to organic page analytics, follower statistics, post performance, and audience demographics for your organization's LinkedIn Page, as well as personal analytics for individual Member Profiles.

<img height="50" src="https://mintcdn.com/nekt/Tq9V5uN_WATiFGnJ/assets/logo/logo-linkedin.png?fit=max&auto=format&n=Tq9V5uN_WATiFGnJ&q=85&s=9381b948fa1dbf0d4290344b3d839a50" data-path="assets/logo/logo-linkedin.png" />

<Note>
  This connector extracts **organic** data from your LinkedIn Organization Page or authenticated Member Profile. For paid advertising data, see the [LinkedIn Ads](/sources/linkedin-ads) connector.
</Note>

## Configuring LinkedIn as a Source

In the [Sources](https://app.nekt.ai/sources) tab, click on the "Add source" button located on the top right of your screen. Then, select the LinkedIn option from the list of connectors.

Click **Next** and you'll be prompted to add your access.

### 1. Add account access

You'll need to authorize Nekt to access your LinkedIn data. Click on the **LinkedIn Authorization** button and log in with your LinkedIn account.

<Warning>
  If you intend to extract data from an Organization Page, make sure you're logged in with a LinkedIn account that has **Admin** or **Content Admin** access to that specific page.
</Warning>

Once you authorize your account, add the following information:

* **Extract data from organization account**: (Default: disabled) When enabled, extracts data from a LinkedIn organization page (posts, followers, page statistics). When disabled, extracts analytics data from the authenticated member's personal profile.

* **Organization ID**: (Conditional) The LinkedIn organization ID you want to extract data from. This is required only if you enabled the option to extract data from an organization account. This is the numeric ID that identifies your company page.

* **Start Date**: The earliest date from which records will be synced. Note that LinkedIn only returns up to **1 year of historical data** for daily reports.

* **Lookback Window**: (Default: 30 days) Number of days to look back on each incremental run for the posts stream. This is applicable if extracting organization data. It ensures post statistics stay up to date for recently published posts. The lookback ensures that posts modified in the last N days have their latest metrics captured, while also preventing data loss during gaps between runs.

<Accordion title="Finding Your Organization ID">
  This is how you can find your Organization ID:

  1. **From the Admin View URL**:
     * Go to your LinkedIn Company Page
     * Click on "Admin tools" or access the admin view
     * Look at the URL - it will contain something like `/company/12345678/admin/`
     * The number (e.g., `12345678`) is your Organization ID
</Accordion>

Once you're done, click **Next**.

### 2. Select streams

Choose which data streams you want to sync. For faster extractions, select only the streams that are relevant to your analysis. You can select entire groups of streams or pick specific ones.

<Note>
  The available streams depend on your configuration (whether you selected to extract data from an organization account or left it disabled for member profile data).
</Note>

**Available Streams (Organization):**

*Organization Data:*

* Organization Details - Company profile information

*Daily Statistics (Time-series):*

* Daily Follower Statistics - Daily follower gains
* Daily Page Statistics - Daily page views and visitor analytics
* Daily Share Statistics - Daily aggregate engagement metrics

*Lifetime Statistics (Current Snapshot):*

* Lifetime Follower Statistics - Total follower count
* Lifetime Page Statistics - Lifetime page views and analytics
* Lifetime Share Statistics - Lifetime engagement metrics

*Content:*

* Posts - All posts from your page
* Post Statistics - Individual post performance

**Available Streams (Member Profile):**

*Member Profile Analytics:*

* Daily Member Follower Statistics - Daily follower count for the member
* Lifetime Member Follower Count - Total follower count for the member
* Daily Member Post Analytics - Daily post engagement metrics for the member
* Total Member Post Analytics - Lifetime post engagement metrics for the member

> Tip: The stream can be found more easily by typing its name.

Select the streams and click **Next**.

### 3. Configure data streams

Customize how you want your data to appear in your catalog. Select the desired layer where the data will be placed, a folder to organize it inside the layer, a name for each table (which will contain the fetched data) and the type of sync.

* **Layer**: Choose between the existing layers on your catalog. This is where you will find your new extracted tables as the extraction runs successfully.
* **Folder**: A folder can be created inside the selected layer to group all tables being created from this new data source.
* **Table name**: We suggest a name, but feel free to customize it. You have the option to add a **prefix** to all tables at once and make this process faster!
* **Sync Type**: You can choose between INCREMENTAL and FULL\_TABLE.
  * Incremental: Every time the extraction happens, we'll get only the new data - which is good if, for example, you want to keep every record ever fetched.
  * Full table: Every time the extraction happens, we'll get the current state of the data - which is good if, for example, you don't want to have deleted data in your catalog.

Once you are done configuring, click **Next**.

### 4. Configure data source

Describe your data source for easy identification within your organization, not exceeding 140 characters.

To define your [Trigger](https://docs.nekt.com/runs/scheduling-and-triggers), consider how often you want data to be extracted from this source. This decision usually depends on how frequently you need the new table data updated (every day, once a week, or only at specific times).

Optionally, you can define some additional settings:

* Configure Delta Log Retention and determine for how long we should store old states of this table as it gets updated. Read more about this resource [here](https://docs.nekt.com/get-started/core-concepts/resource-control).
* Determine when to execute an **Additional [Full Sync](https://docs.nekt.com/get-started/core-concepts/types-of-sync#additional-full-sync)**. This will complement the incremental data extractions, ensuring that your data is completely synchronized with your source every once in a while.

Once you are ready, click **Next** to finalize the setup.

### 5. Check your new source

You can view your new source on the [Sources](https://app.nekt.ai/sources) page. If needed, manually trigger the source extraction by clicking on the arrow button. Once executed, your data will appear in your Catalog.

<Warning>For you to be able to see it on your [Catalog](https://app.nekt.ai/catalog), you need at least one successful source run.</Warning>

# Streams and Fields

Below you'll find all available data streams from LinkedIn and their corresponding fields:

<AccordionGroup>
  <Accordion title="Organization Details">
    Company profile information for your LinkedIn organization.

    | Field                     | Type    | Description                                           |
    | :------------------------ | :------ | :---------------------------------------------------- |
    | `id`                      | Integer | The LinkedIn numeric organization ID                  |
    | `urn`                     | String  | URN for the organization                              |
    | `vanityName`              | String  | The LinkedIn public (vanity) name                     |
    | `localizedName`           | String  | The localized name of the organization                |
    | `localizedDescription`    | String  | Localized description of the organization             |
    | `organizationType`        | String  | The organization type (e.g., PRIVATELY\_HELD)         |
    | `primaryOrganizationType` | String  | Primary type (e.g., BRAND, NONE)                      |
    | `staffCountRange`         | String  | Organization staff count range                        |
    | `foundedOn`               | Object  | Founding information with year                        |
    | `name`                    | Object  | Structured name data with localized variants          |
    | `description`             | Object  | Structured description with localized variants        |
    | `website`                 | Object  | Structured website URLs with localized variants       |
    | `localizedWebsite`        | String  | Localized website URL                                 |
    | `specialties`             | Array   | List of specialties for the organization              |
    | `localizedSpecialties`    | Array   | Localized specialties                                 |
    | `alternativeNames`        | Array   | Alternative names for the organization                |
    | `locations`               | Array   | Array of organization locations with address and type |
    | `logoV2`                  | Object  | Organization logo (cropped, original, cropInfo)       |
    | `coverPhotoV2`            | Object  | Cover photo (cropped, original, cropInfo)             |
    | `defaultLocale`           | Object  | Default locale (country, language)                    |
    | `created`                 | Object  | Creation metadata (actor, time)                       |
    | `lastModified`            | Object  | Last modification metadata (actor, time)              |
    | `versionTag`              | String  | Version tag of the record                             |
    | `autoCreated`             | Boolean | Whether the organization was auto-created             |
    | `groups`                  | Array   | List of group URNs associated with this organization  |
  </Accordion>

  <Accordion title="Daily Follower Statistics">
    Daily follower statistics for your organization, including follower gains.

    | Field                             | Type   | Description                                          |
    | :-------------------------------- | :----- | :--------------------------------------------------- |
    | `date`                            | Date   | The date of the report (replication key)             |
    | `organizationalEntity`            | String | The organization URN                                 |
    | `timeRange`                       | Object | Time range for the statistics (start/end timestamps) |
    | `followerGains`                   | Object | Daily follower changes with organic and paid counts  |
    | `followerCountsByAssociationType` | Array  | Followers by relationship (employee, etc.)           |
    | `followerCountsByGeoCountry`      | Array  | Followers by country                                 |
    | `followerCountsByFunction`        | Array  | Followers by job function                            |
    | `followerCountsByIndustry`        | Array  | Followers by industry                                |
    | `followerCountsByGeo`             | Array  | Followers by market area/region                      |
    | `followerCountsBySeniority`       | Array  | Followers by seniority level                         |
    | `followerCountsByStaffCountRange` | Array  | Followers by company size                            |
  </Accordion>

  <Accordion title="Lifetime Follower Statistics">
    Total follower count for your organization (current snapshot).

    | Field             | Type    | Description                              |
    | :---------------- | :------ | :--------------------------------------- |
    | `date`            | Date    | The date of the report                   |
    | `firstDegreeSize` | Integer | Total number of followers (network size) |

    <Note>
      This stream provides the current total follower count, not historical data. Use Daily Follower Statistics for time-series follower growth data.
    </Note>
  </Accordion>

  <Accordion title="Daily Page Statistics">
    Daily page view and click statistics for your organization's LinkedIn page, with breakdowns by visitor demographics.

    | Field                             | Type   | Description                                          |
    | :-------------------------------- | :----- | :--------------------------------------------------- |
    | `date`                            | Date   | The date of the report (replication key)             |
    | `organization`                    | String | The organization URN                                 |
    | `timeRange`                       | Object | Time range for the statistics (start/end timestamps) |
    | `totalPageStatistics`             | Object | Aggregate statistics with views and clicks           |
    | `allPageViews`                    | Object | Total page views across all devices                  |
    | `allDesktopPageViews`             | Object | All desktop page views                               |
    | `allMobilePageViews`              | Object | All mobile page views                                |
    | `overviewPageViews`               | Object | Overview/home tab views (all devices)                |
    | `desktopOverviewPageViews`        | Object | Desktop overview views                               |
    | `mobileOverviewPageViews`         | Object | Mobile overview views                                |
    | `aboutPageViews`                  | Object | About tab views (all devices)                        |
    | `desktopAboutPageViews`           | Object | Desktop about views                                  |
    | `mobileAboutPageViews`            | Object | Mobile about views                                   |
    | `jobsPageViews`                   | Object | Jobs tab views (all devices)                         |
    | `desktopJobsPageViews`            | Object | Desktop jobs views                                   |
    | `mobileJobsPageViews`             | Object | Mobile jobs views                                    |
    | `careersPageViews`                | Object | Careers tab views (all devices)                      |
    | `desktopCareersPageViews`         | Object | Desktop careers views                                |
    | `mobileCareersPageViews`          | Object | Mobile careers views                                 |
    | `lifeAtPageViews`                 | Object | Life at \[Company] views (all devices)               |
    | `desktopLifeAtPageViews`          | Object | Desktop life at views                                |
    | `mobileLifeAtPageViews`           | Object | Mobile life at views                                 |
    | `productsPageViews`               | Object | Products tab views (all devices)                     |
    | `desktopProductsPageViews`        | Object | Desktop products views                               |
    | `mobileProductsPageViews`         | Object | Mobile products views                                |
    | `peoplePageViews`                 | Object | People tab views (all devices)                       |
    | `desktopPeoplePageViews`          | Object | Desktop people views                                 |
    | `mobilePeoplePageViews`           | Object | Mobile people views                                  |
    | `insightsPageViews`               | Object | Insights tab views (all devices)                     |
    | `desktopInsightsPageViews`        | Object | Desktop insights views                               |
    | `mobileInsightsPageViews`         | Object | Mobile insights views                                |
    | `pageStatisticsByGeoCountry`      | Array  | Views by country                                     |
    | `pageStatisticsByFunction`        | Array  | Views by job function                                |
    | `pageStatisticsByIndustryV2`      | Array  | Views by industry (v2)                               |
    | `pageStatisticsByGeo`             | Array  | Views by region/market area                          |
    | `pageStatisticsBySeniority`       | Array  | Views by seniority                                   |
    | `pageStatisticsByStaffCountRange` | Array  | Views by company size                                |
    | `pageStatisticsByTargetedContent` | Array  | Views by targeted content                            |
  </Accordion>

  <Accordion title="Lifetime Page Statistics">
    Lifetime page view statistics for your organization's LinkedIn page. Same structure as Daily Page Statistics but represents cumulative/lifetime data.

    | Field          | Type   | Description                              |
    | :------------- | :----- | :--------------------------------------- |
    | `date`         | Date   | The date of the report (replication key) |
    | `organization` | String | The organization URN                     |

    Contains the same fields as Daily Page Statistics (`totalPageStatistics`, all page view breakdowns, and demographic breakdowns), but represents lifetime cumulative data rather than daily increments.
  </Accordion>

  <Accordion title="Daily Share Statistics">
    Daily aggregate share and engagement statistics for your organization's content.

    | Field                  | Type   | Description                                                                                         |
    | :--------------------- | :----- | :-------------------------------------------------------------------------------------------------- |
    | `date`                 | Date   | The date of the report (replication key)                                                            |
    | `organizationalEntity` | String | The organization URN                                                                                |
    | `share`                | String | The share URN (blank for aggregate statistics)                                                      |
    | `ugcPost`              | String | The UGC post URN (blank for aggregate statistics)                                                   |
    | `timeRange`            | Object | Time range for the statistics (start/end timestamps)                                                |
    | `totalShareStatistics` | Object | Aggregate engagement metrics with clicks, comments, impressions, likes, shares, and engagement rate |
  </Accordion>

  <Accordion title="Lifetime Share Statistics">
    Lifetime aggregate share and engagement statistics for your organization's content.

    | Field                  | Type   | Description                                                                                          |
    | :--------------------- | :----- | :--------------------------------------------------------------------------------------------------- |
    | `date`                 | Date   | The date of the report (replication key)                                                             |
    | `organizationalEntity` | String | The organization URN                                                                                 |
    | `share`                | String | The share URN (blank for aggregate statistics)                                                       |
    | `ugcPost`              | String | The UGC post URN (blank for aggregate statistics)                                                    |
    | `timeRange`            | Object | Time range for the statistics (start/end timestamps)                                                 |
    | `totalShareStatistics` | Object | Cumulative engagement metrics with clicks, comments, impressions, likes, shares, and engagement rate |
  </Accordion>

  <Accordion title="Posts">
    All posts published by your organization on LinkedIn.

    | Field                       | Type    | Description                                                     |
    | :-------------------------- | :------ | :-------------------------------------------------------------- |
    | `id`                        | String  | The post ID (URN)                                               |
    | `author`                    | String  | The author URN (organization)                                   |
    | `createdAt`                 | Integer | Creation timestamp (epoch milliseconds)                         |
    | `publishedAt`               | Integer | Publication timestamp (epoch milliseconds)                      |
    | `lastModifiedAt`            | Integer | Last modification timestamp (replication key)                   |
    | `lifecycleState`            | String  | Post state (PUBLISHED, DRAFT, etc.)                             |
    | `commentary`                | String  | The post text/caption                                           |
    | `content`                   | Object  | The attached content object (media, article, poll, etc.)        |
    | `contentCallToActionLabel`  | String  | CTA button label                                                |
    | `contentLandingPage`        | String  | CTA landing page URL                                            |
    | `visibility`                | String  | Visibility setting (PUBLIC, CONNECTIONS, etc.)                  |
    | `distribution`              | Object  | Distribution settings including feed distribution and targeting |
    | `adContext`                 | Object  | Ad information if post is sponsored                             |
    | `reshareContext`            | Object  | If this is a reshare, contains parent/root references           |
    | `isReshareDisabledByAuthor` | Boolean | Whether resharing is disabled                                   |
    | `lifecycleStateInfo`        | Object  | Additional state information                                    |
  </Accordion>

  <Accordion title="Post Statistics">
    Individual post performance metrics. This stream is a child of Posts, providing statistics for each post.

    | Field                  | Type    | Description                                                                                                              |
    | :--------------------- | :------ | :----------------------------------------------------------------------------------------------------------------------- |
    | `postLastModifiedAt`   | Integer | The last modified time of the post (replication key)                                                                     |
    | `organizationalEntity` | String  | The organization URN                                                                                                     |
    | `postId`               | String  | The post ID (URN) - links to the Posts stream                                                                            |
    | `share`                | String  | The share URN (for legacy shares)                                                                                        |
    | `ugcPost`              | String  | The UGC post URN                                                                                                         |
    | `timeRange`            | Object  | Time range for the statistics (start/end timestamps)                                                                     |
    | `totalShareStatistics` | Object  | Post performance metrics including clicks, comments, engagement rate, impressions, likes, shares, and unique impressions |
  </Accordion>

  <Accordion title="Daily Member Follower Statistics">
    Daily follower count for the authenticated member. Returns one row per date with the number of new followers gained that day.

    | Field                    | Type    | Description                                 |
    | :----------------------- | :------ | :------------------------------------------ |
    | `date`                   | Date    | The date of the follower data point         |
    | `member_followers_count` | Integer | Number of new followers gained on this date |
  </Accordion>

  <Accordion title="Lifetime Member Follower Count">
    Lifetime total follower count for the authenticated member.

    | Field                    | Type    | Description                        |
    | :----------------------- | :------ | :--------------------------------- |
    | `date`                   | Date    | The date when the data was fetched |
    | `member_followers_count` | Integer | Total number of followers          |
  </Accordion>

  <Accordion title="Daily Member Post Analytics">
    Daily aggregated post analytics for the authenticated member.

    | Field                | Type    | Description                                   |
    | :------------------- | :------ | :-------------------------------------------- |
    | `date`               | Date    | The date of the analytics data point          |
    | `impressions`        | Integer | Number of times posts were displayed          |
    | `reactions`          | Integer | Number of reactions received                  |
    | `comments`           | Integer | Number of comments received                   |
    | `reshares`           | Integer | Number of reshares/reposts                    |
    | `post_saves`         | Integer | Number of times posts were saved              |
    | `post_sends`         | Integer | Number of times posts were sent via messaging |
    | `premium_cta_clicks` | Integer | Number of premium CTA button clicks           |
  </Accordion>

  <Accordion title="Total Member Post Analytics">
    Lifetime aggregated post analytics for the authenticated member. Returns a single row with the total count for each metric across all posts.

    | Field                | Type    | Description                        |
    | :------------------- | :------ | :--------------------------------- |
    | `date`               | Date    | The date when the data was fetched |
    | `impressions`        | Integer | Total number of impressions        |
    | `members_reached`    | Integer | Total unique members reached       |
    | `reactions`          | Integer | Total number of reactions          |
    | `comments`           | Integer | Total number of comments           |
    | `reshares`           | Integer | Total number of reshares/reposts   |
    | `post_saves`         | Integer | Total number of post saves         |
    | `post_sends`         | Integer | Total number of post sends         |
    | `link_clicks`        | Integer | Total number of link clicks        |
    | `premium_cta_clicks` | Integer | Total premium CTA clicks           |
  </Accordion>
</AccordionGroup>

# Data Model

The following diagram illustrates the relationships between the core data streams in LinkedIn. The arrows indicate the join keys that link the different entities.

```mermaid theme={null}
graph TD;
    subgraph "Organization Profile"
        OrgDetails("Organization Details");
    end

    subgraph "Daily Analytics"
        DailyFollower("Daily Follower Statistics");
        DailyPage("Daily Page Statistics");
        DailyShare("Daily Share Statistics");
    end

    subgraph "Lifetime Analytics"
        LifetimeFollower("Lifetime Follower Statistics");
        LifetimePage("Lifetime Page Statistics");
        LifetimeShare("Lifetime Share Statistics");
    end

    subgraph "Content"
        Posts("Posts");
        PostStats("Post Statistics");
    end

    subgraph "Member Profile Analytics"
        DailyMemberFollowers("Daily Member Follower Statistics");
        LifetimeMemberFollowers("Lifetime Member Follower Count");
        DailyMemberPosts("Daily Member Post Analytics");
        TotalMemberPosts("Total Member Post Analytics");
    end

    OrgDetails -- "id/urn" --> Organization["Organization ID"];
    DailyFollower -- "organizationalEntity" --> Organization;
    DailyPage -- "organization" --> Organization;
    DailyShare -- "organizationalEntity" --> Organization;
    LifetimeFollower -- "organization_id" --> Organization;
    LifetimePage -- "organization" --> Organization;
    LifetimeShare -- "organizationalEntity" --> Organization;
    Posts -- "author" --> Organization;
    PostStats -- "postId" --> Posts;
    DailyMemberFollowers -- "date" --> MemberProfile["Member Profile (Authenticated)"];
    LifetimeMemberFollowers -- "date" --> MemberProfile;
    DailyMemberPosts -- "date" --> MemberProfile;
    TotalMemberPosts -- "date" --> MemberProfile;
```

# Use Cases for Data Analysis

This guide outlines valuable business intelligence use cases when consolidating LinkedIn organic data, along with ready-to-use SQL queries that you can run on [Explorer](https://app.nekt.ai/explorer).

## Content Performance Analysis

### 1. Post Engagement Overview

Track the performance of your LinkedIn posts to identify top-performing content.

**Business Value:**

* Identify which content types drive the most engagement
* Understand optimal posting patterns
* Inform content strategy with data-driven insights

<Accordion title="SQL query" defaultOpen>
  <Tabs>
    <Tab title="AWS">
      ```sql theme={null}
      WITH post_metrics AS (
          SELECT
              p.id AS post_id,
              p.commentary AS post_text,
              FROM_UNIXTIME(p."publishedAt" / 1000) AS published_date,
              p."lifecycleState" AS status,
              CASE
                  WHEN p.content.media IS NOT NULL THEN 'MEDIA'
                  WHEN p.content.article IS NOT NULL THEN 'ARTICLE'
                  WHEN p.content.poll IS NOT NULL THEN 'POLL'
                  WHEN p.content."multiImage" IS NOT NULL THEN 'MULTI_IMAGE'
                  WHEN p.content.carousel IS NOT NULL THEN 'CAROUSEL'
                  ELSE 'TEXT_ONLY'
              END AS content_type,
              ps."totalShareStatistics"."impressionCount" AS impressions,
              ps."totalShareStatistics"."uniqueImpressionsCount" AS unique_impressions,
              ps."totalShareStatistics"."clickCount" AS clicks,
              ps."totalShareStatistics"."likeCount" AS likes,
              ps."totalShareStatistics"."commentCount" AS comments,
              ps."totalShareStatistics"."shareCount" AS shares,
              ps."totalShareStatistics".engagement AS engagement_rate
          FROM
              nekt_raw.linkedin_posts p
              LEFT JOIN nekt_raw.linkedin_post_statistics ps 
                  ON p.id = ps."postId"
          WHERE
              p."lifecycleState" = 'PUBLISHED'
      )
      SELECT
          post_id,
          SUBSTRING(post_text, 1, 100) AS post_preview,
          published_date,
          content_type,
          impressions,
          unique_impressions,
          clicks,
          likes,
          comments,
          shares,
          ROUND(engagement_rate * 100, 2) AS engagement_rate_pct,
          (likes + comments + shares) AS total_engagements
      FROM
          post_metrics
      ORDER BY
          total_engagements DESC
      LIMIT 20
      ```
    </Tab>

    <Tab title="GCP">
      ```sql theme={null}
      WITH post_metrics AS (
          SELECT
              p.id AS post_id,
              p.commentary AS post_text,
              TIMESTAMP_MILLIS(CAST(p.publishedAt AS INT64)) AS published_date,
              p.lifecycleState AS status,
              CASE
                  WHEN p.content.media IS NOT NULL THEN 'MEDIA'
                  WHEN p.content.article IS NOT NULL THEN 'ARTICLE'
                  WHEN p.content.poll IS NOT NULL THEN 'POLL'
                  WHEN p.content.multiImage IS NOT NULL THEN 'MULTI_IMAGE'
                  WHEN p.content.carousel IS NOT NULL THEN 'CAROUSEL'
                  ELSE 'TEXT_ONLY'
              END AS content_type,
              ps.totalShareStatistics.impressionCount AS impressions,
              ps.totalShareStatistics.uniqueImpressionsCount AS unique_impressions,
              ps.totalShareStatistics.clickCount AS clicks,
              ps.totalShareStatistics.likeCount AS likes,
              ps.totalShareStatistics.commentCount AS comments,
              ps.totalShareStatistics.shareCount AS shares,
              ps.totalShareStatistics.engagement AS engagement_rate
          FROM
              `nekt_raw.linkedin_posts` p
              LEFT JOIN `nekt_raw.linkedin_post_statistics` ps 
                  ON p.id = ps.postId
          WHERE
              p.lifecycleState = 'PUBLISHED'
      )
      SELECT
          post_id,
          SUBSTR(post_text, 1, 100) AS post_preview,
          published_date,
          content_type,
          impressions,
          unique_impressions,
          clicks,
          likes,
          comments,
          shares,
          ROUND(engagement_rate * 100, 2) AS engagement_rate_pct,
          (likes + comments + shares) AS total_engagements
      FROM
          post_metrics
      ORDER BY
          total_engagements DESC
      LIMIT 20
      ```
    </Tab>
  </Tabs>
</Accordion>

<Accordion title="Sample Result">
  | post\_id              | post\_preview                                | published\_date     | content\_type | impressions | unique\_impressions | clicks | likes | comments | shares | engagement\_rate\_pct | total\_engagements |
  | --------------------- | -------------------------------------------- | ------------------- | ------------- | ----------- | ------------------- | ------ | ----- | -------- | ------ | --------------------- | ------------------ |
  | urn:li:share:123456   | We're excited to announce our new product... | 2024-11-15 14:30:00 | MEDIA         | 45,230      | 38,450              | 1,234  | 892   | 156      | 78     | 4.82                  | 1,126              |
  | urn:li:ugcPost:789012 | Join us for our upcoming webinar on...       | 2024-11-12 09:00:00 | ARTICLE       | 32,150      | 28,320              | 956    | 543   | 89       | 45     | 3.21                  | 677                |
  | urn:li:share:345678   | Proud to share that our team has been...     | 2024-11-10 16:45:00 | MULTI\_IMAGE  | 28,900      | 24,670              | 445    | 678   | 234      | 123    | 5.12                  | 1,035              |
</Accordion>

### 2. Follower Growth Analysis

Track your organization's follower growth over time and understand the source of new followers.

**Business Value:**

* Monitor organic vs paid follower acquisition
* Track growth trends over time
* Measure the impact of content and campaigns on follower growth

<Accordion title="SQL query" defaultOpen>
  <Tabs>
    <Tab title="AWS">
      ```sql theme={null}
      WITH daily_followers AS (
          SELECT
              DATE(date) AS report_date,
              "followerGains"."organicFollowerGain" AS organic_gained,
              "followerGains"."paidFollowerGain" AS paid_gained,
              ("followerGains"."organicFollowerGain" + "followerGains"."paidFollowerGain") AS total_gained
          FROM
              nekt_raw.linkedin_daily_follower_statistics
          WHERE
              date >= CURRENT_DATE - INTERVAL '30' DAY
      ),
      running_totals AS (
          SELECT
              report_date,
              organic_gained,
              paid_gained,
              total_gained,
              SUM(total_gained) OVER (ORDER BY report_date) AS cumulative_growth,
              AVG(total_gained) OVER (
                  ORDER BY report_date 
                  ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
              ) AS seven_day_avg
          FROM
              daily_followers
      )
      SELECT
          report_date,
          organic_gained,
          paid_gained,
          total_gained,
          cumulative_growth,
          ROUND(seven_day_avg, 1) AS seven_day_moving_avg,
          ROUND(organic_gained * 100.0 / NULLIF(total_gained, 0), 1) AS organic_pct
      FROM
          running_totals
      ORDER BY
          report_date DESC
      ```
    </Tab>

    <Tab title="GCP">
      ```sql theme={null}
      WITH daily_followers AS (
          SELECT
              DATE(date) AS report_date,
              followerGains.organicFollowerGain AS organic_gained,
              followerGains.paidFollowerGain AS paid_gained,
              (followerGains.organicFollowerGain + followerGains.paidFollowerGain) AS total_gained
          FROM
              `nekt_raw.linkedin_daily_follower_statistics`
          WHERE
              date >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)
      ),
      running_totals AS (
          SELECT
              report_date,
              organic_gained,
              paid_gained,
              total_gained,
              SUM(total_gained) OVER (ORDER BY report_date) AS cumulative_growth,
              AVG(total_gained) OVER (
                  ORDER BY report_date 
                  ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
              ) AS seven_day_avg
          FROM
              daily_followers
      )
      SELECT
          report_date,
          organic_gained,
          paid_gained,
          total_gained,
          cumulative_growth,
          ROUND(seven_day_avg, 1) AS seven_day_moving_avg,
          ROUND(SAFE_DIVIDE(organic_gained * 100.0, total_gained), 1) AS organic_pct
      FROM
          running_totals
      ORDER BY
          report_date DESC
      ```
    </Tab>
  </Tabs>
</Accordion>

<Accordion title="Sample Result">
  | report\_date | organic\_gained | paid\_gained | total\_gained | cumulative\_growth | seven\_day\_moving\_avg | organic\_pct |
  | ------------ | --------------- | ------------ | ------------- | ------------------ | ----------------------- | ------------ |
  | 2024-11-27   | 45              | 12           | 57            | 1,234              | 48.3                    | 78.9         |
  | 2024-11-26   | 38              | 8            | 46            | 1,177              | 46.7                    | 82.6         |
  | 2024-11-25   | 52              | 15           | 67            | 1,131              | 45.1                    | 77.6         |
  | 2024-11-24   | 28              | 5            | 33            | 1,064              | 43.9                    | 84.8         |
  | 2024-11-23   | 31              | 7            | 38            | 1,031              | 44.2                    | 81.6         |
</Accordion>

### 3. Page Visitor Demographics

Analyze who is visiting your LinkedIn page to understand your audience.

**Business Value:**

* Understand your audience composition
* Identify high-value visitor segments
* Inform content targeting decisions

<Accordion title="SQL query" defaultOpen>
  <Tabs>
    <Tab title="AWS">
      ```sql theme={null}
      WITH seniority_stats AS (
          SELECT
              s.seniority,
              SUM(s."pageStatistics".views."allPageViews"."pageViews") AS total_views,
              SUM(s."pageStatistics".views."allPageViews"."uniquePageViews") AS unique_views
          FROM
              nekt_raw.linkedin_daily_page_statistics ps
              CROSS JOIN UNNEST(ps."pageStatisticsBySeniority") AS t(s)
          WHERE
              DATE(ps.date) >= CURRENT_DATE - INTERVAL '30' DAY
          GROUP BY
              s.seniority
      ),
      total AS (
          SELECT SUM(total_views) AS grand_total FROM seniority_stats
      )
      SELECT
          seniority,
          total_views,
          unique_views,
          ROUND(total_views * 100.0 / grand_total, 1) AS pct_of_total
      FROM
          seniority_stats, total
      ORDER BY
          total_views DESC
      ```
    </Tab>

    <Tab title="GCP">
      ```sql theme={null}
      WITH seniority_stats AS (
          SELECT
              s.seniority,
              SUM(s.pageStatistics.views.allPageViews.pageViews) AS total_views,
              SUM(s.pageStatistics.views.allPageViews.uniquePageViews) AS unique_views
          FROM
              `nekt_raw.linkedin_daily_page_statistics` ps,
              UNNEST(ps.pageStatisticsBySeniority) AS s
          WHERE
              DATE(ps.date) >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)
          GROUP BY
              s.seniority
      ),
      total AS (
          SELECT SUM(total_views) AS grand_total FROM seniority_stats
      )
      SELECT
          seniority,
          total_views,
          unique_views,
          ROUND(SAFE_DIVIDE(total_views * 100.0, grand_total), 1) AS pct_of_total
      FROM
          seniority_stats, total
      ORDER BY
          total_views DESC
      ```
    </Tab>
  </Tabs>
</Accordion>

<Accordion title="Sample Result">
  | seniority          | total\_views | unique\_views | pct\_of\_total |
  | ------------------ | ------------ | ------------- | -------------- |
  | urn:li:seniority:5 | 12,450       | 9,230         | 28.4           |
  | urn:li:seniority:6 | 9,870        | 7,456         | 22.5           |
  | urn:li:seniority:4 | 8,234        | 6,123         | 18.8           |
  | urn:li:seniority:3 | 6,543        | 4,890         | 14.9           |
  | urn:li:seniority:7 | 4,321        | 3,210         | 9.9            |
</Accordion>

# Implementation Notes

<AccordionGroup>
  <Accordion title="Data Freshness">
    LinkedIn analytics data typically has a delay of 24-48 hours. The most recent data available may be from 1-2 days ago.

    * **Daily reports**: Updated once per day
    * **Post statistics**: Updated as engagement occurs, with some delay
    * **Lifetime demographics**: Represent current state, not historical
  </Accordion>

  <Accordion title="Historical Data Limits">
    LinkedIn limits historical data access:

    * **Daily statistics** (Follower, Page, Share): Up to **1 year** of historical data
    * **Posts**: All published posts are available
    * **Post statistics**: Available for all posts, but metrics are cumulative (not daily)
  </Accordion>

  <Accordion title="API Permissions">
    This connector requires the following LinkedIn permissions depending on the streams extracted:

    * `r_organization_social` - Read organization posts and social data
    * `r_member_profileAnalytics` - Read analytics for the authenticated member's profile
    * `r_member_postAnalytics` - Read analytics for the authenticated member's posts
    * Access to **Community Management API**

    If extracting data from an organization, the LinkedIn account used for authorization must have **Admin** or **Content Admin** access to the organization page.
  </Accordion>

  <Accordion title="URN Format">
    LinkedIn uses URNs (Uniform Resource Names) to identify entities:

    * **Organizations**: `urn:li:organization:{id}`
    * **Posts**: `urn:li:share:{id}` or `urn:li:ugcPost:{id}`
    * **Seniority levels**: `urn:li:seniority:{id}`
    * **Industries**: `urn:li:industry:{id}`
    * **Functions**: `urn:li:function:{id}`
    * **Countries**: `urn:li:geo:{id}` or `urn:li:country:{code}`

    These URNs are used as identifiers and can be decoded to get the underlying IDs.
  </Accordion>

  <Accordion title="Engagement Rate Calculation">
    LinkedIn's `engagement` field is calculated as:

    ```
    engagement = (clicks + likes + comments + shares) / impressions
    ```

    This is returned as a decimal (e.g., 0.0482 = 4.82%). Multiply by 100 to get the percentage.
  </Accordion>

  <Accordion title="Incremental Sync with Lookback">
    The Posts and Post Statistics streams support incremental sync with a lookback window:

    * **Posts**: Uses `lastModifiedAt` as the replication key for incremental sync
    * **Post Statistics**: Uses `postLastModifiedAt` as the replication key, derived from the parent post's modification time
    * **Lookback Window**: Configurable number of days (default: 30) to look back on each run to ensure recently modified posts have up-to-date statistics
    * **API Rate Limiting**: The connector gracefully handles LinkedIn's daily rate limits (including both member-level and resource-level application quotas). It stops extraction when these limits are reached and resumes from the current state on the next run

    This ensures that post performance metrics stay current for recently published content while maintaining efficient incremental syncs.
  </Accordion>
</AccordionGroup>

## Skills for agents

<Snippet file="agent-skills-intro.mdx" />

<Card title="Download LinkedIn skills file" icon="wand-magic-sparkles" href="/sources/linkedin.md">
  LinkedIn connector documentation as plain markdown, for use in AI agent contexts.
</Card>
