LinkedIn Learning
Visualize LinkedIn Learning courses, learning paths, videos, content taxonomy, learners, and per-learner engagement (completions, views, progress) in the JupiterOne graph. Track training completion as compliance evidence, identify gaps in skill coverage, and map learners to the content they engage with through queries and alerts.
- Installation
- Authorization
- Data Model
- Types
- Release Notes
Installation
LinkedIn Learning credentials are scoped to two key types — Content
(learningAssets + learningClassifications) and Report
(learningActivityReports). The integration accepts up to two credential
pairs, one per scope, but only one pair is required. See the
Authorization tab for the full breakdown
of how credential combinations behave.
Prerequisites
- A LinkedIn Learning Enterprise account.
- An administrator with permission to Generate LinkedIn Learning REST API Applications from the LinkedIn Learning admin console.
- Access to JupiterOne with permission to configure integrations.
Generate API credentials in LinkedIn Learning
LinkedIn provisions credentials at the application level. You can either create one application with both key types selected (recommended for new installs) or create two separate applications, one per scope.
-
Sign in to LinkedIn Learning as an administrator. If you are not already in the Admin area, click Go to Admin.
-
In the side navigation, open Access content and reports via API and expand Generate LinkedIn Learning REST API Application.
-
Click Add application.
-
Enter an Application Name (e.g. JupiterOne Integration) and an Application description (e.g. Reads LinkedIn Learning content and activity into JupiterOne for compliance reporting).
-
Under Choose keys, select Content, Report, or both depending on which data surface you want to ingest:
- Content authorizes the asset catalog: courses, learning paths, videos, and the content taxonomy.
- Report authorizes per-learner engagement: completions, views, progress, and seconds-viewed.
-
Click Next and accept the Terms and Conditions.
-
Copy the generated Client ID and Client Secret — save them securely. You will paste these values into JupiterOne in the next section.
tipIf you create one application with both Content and Report keys selected, you only have to copy a single pair. The same
Client ID/Client Secretauthorizes every endpoint and you only need to fill one of the two pairs in JupiterOne. -
(Optional) Repeat the steps above if your organization requires separate applications for the two scopes (e.g. because Content and Report access are owned by different teams). You will end up with two distinct credential pairs, one per scope.
Configure the integration in JupiterOne
To install the LinkedIn Learning integration in JupiterOne, navigate to the Integrations tab in JupiterOne and select LinkedIn Learning. Click New Instance to begin configuring your integration.
Creating a LinkedIn Learning instance requires the following:
- The Account Name used to identify the LinkedIn Learning account in
JupiterOne. Ingested entities will have this value stored in
tag.AccountNamewhen theAccountNametoggle is enabled. - Description to assist in identifying the integration instance, if desired.
- Polling Interval that you feel is sufficient for your monitoring
needs. You may leave this as
DISABLEDand manually execute the integration.
Authentication fields
Fill in at least one of the credential pairs below. For full guidance on which combination matches your application setup, see the Authorization tab.
| Field | Required | Description |
|---|---|---|
| Content Client ID | Conditional — at least one pair is required. | OAuth Client ID for the LinkedIn Learning application authorized for the Content scope. If your application has both Content and Report keys selected, filling this pair alone authorizes every endpoint. |
| Content Client Secret | Required when Content Client ID is provided. | OAuth Client Secret paired with Content Client ID. |
| Report Client ID | Conditional — at least one pair is required. | OAuth Client ID for the LinkedIn Learning application authorized for the Report scope. Only set this when you generated a separate application for the Report keys. |
| Report Client Secret | Required when Report Client ID is provided. | OAuth Client Secret paired with Report Client ID. |
Advanced — Activity Lookback Days
The integration's user-activity steps query LinkedIn's
learningActivityReports endpoint, which caps each request at a 14-day
window. The integration transparently chunks longer lookback windows into
multiple ≤14-day requests on each sync.
| Field | Default | Options | Description |
|---|---|---|---|
| Activity Lookback Days | 14 | 14, 30, 90, 180, 365 | How far back to fetch learning activity on each sync. Larger values increase the number of API calls per run: 14 days → 1 window per activity step; 365 days → 27 windows per activity step. |
How it affects data volume: Larger lookback windows ingest more
historical engagement, which produces a denser User -[:ASSIGNED]-> Training
relationship graph but multiplies the request count per sync. For
day-to-day compliance reporting, 14 is sufficient on a daily polling
cadence. Choose 90 or longer only when you need a historical backfill or
when your polling cadence is weekly/monthly.
Click Create once all values are provided to finalize the integration.
Next steps
Now that your integration instance has been configured, it will begin running on the polling interval you provided, populating data within JupiterOne. Continue on to our Instance management guide to learn more about working with and editing integration instances.
Authorization
The LinkedIn Learning integration authenticates against the LinkedIn API
using the OAuth 2.0 client_credentials flow (also known as
"2-legged OAuth"). Every endpoint the integration touches —
learningAssets, learningClassifications, and learningActivityReports
— uses the same auth mechanism: the configured Client ID and
Client Secret are exchanged for a 30-minute bearer token at
https://www.linkedin.com/oauth/v2/accessToken, and the token is sent as
Authorization: Bearer <token> on subsequent requests to
https://api.linkedin.com/v2/. Tokens are re-minted automatically on
expiry so long collection runs survive a token rollover.
Why there are two credential pairs
LinkedIn Learning's REST API is partitioned into two key types:
| Key type | Endpoints authorized | JupiterOne data ingested |
|---|---|---|
| Content | learningAssets, learningClassifications | Courses, learning paths, videos, content taxonomy (libraries / subjects / topics), asset → tag links |
| Report | learningActivityReports | Learners, per-learner content engagement (completions, views, progress, seconds-viewed), user → content links |
An administrator generates each key type when creating a LinkedIn Learning REST API Application in the LinkedIn admin console. They can either:
- Create one application with both Content and Report boxes
checked → a single
Client ID/Client Secretpair that authorizes every endpoint, or - Create two separate applications, one per key type → two distinct pairs, each scoped to its respective endpoints.
The integration accepts up to two credential pairs (one labeled Content, one labeled Report) to cover either provisioning style. At minimum, one pair is required.
How the integration resolves credentials
When the integration calls a LinkedIn endpoint, it picks the credential pair according to which scope the endpoint belongs to. If only one pair is configured, that pair is used for both scopes (a single combined-scope application is the most common case and works out of the box without typing your credentials twice).
| Endpoint scope | Preferred pair | Fallback pair |
|---|---|---|
| Content | Content pair | Report pair (if no Content pair is configured) |
| Report | Report pair | Content pair (if no Report pair is configured) |
Outcomes by setup
The following matrix summarizes what to expect for each provisioning shape:
| Your LinkedIn application setup | What to fill in JupiterOne | Behavior at runtime |
|---|---|---|
| One application with both Content and Report keys checked | Fill either the Content pair or the Report pair — not both. | The same credentials authorize every endpoint. One OAuth token is minted per integration run. Every step ingests data normally. |
| One application with only Content keys checked | Fill the Content pair only. | Asset and classification steps ingest data normally. Report steps proceed at runtime but the Report endpoints return 403 Forbidden because the credentials lack Report scope. Those steps fail with an authorization error — switch to a combined application or add Report keys to fix this. |
| One application with only Report keys checked | Fill the Report pair only. | Mirror of the previous row: Report steps work; asset and classification steps return 403 Forbidden. |
| Two separate applications (one for Content, one for Report) | Fill both the Content pair and the Report pair. | Each scope uses its labeled credentials. Two OAuth tokens are minted per integration run (one per scope). Every step ingests data normally. |
What gets stored and what doesn't
The integration:
- Reads the four credential fields from your integration configuration.
- Sends them to LinkedIn's OAuth endpoint as form-encoded body
parameters (
grant_type=client_credentials,client_id=...,client_secret=...) only when it needs to mint or re-mint a token. - Stores the resulting bearer token in memory for the lifetime of the integration job (~30 minutes maximum, since LinkedIn caps token TTL at 30 minutes).
- Does not persist the bearer token across runs; a fresh token is minted at the start of each integration job.
The Client Secret fields are masked in the JupiterOne UI and are
encrypted at rest in JupiterOne's configuration store.
Validation behavior at save time
When you save an integration configuration, JupiterOne verifies that each explicitly provided credential pair can mint a token. If only one pair is filled, only one token is minted at save time; the cross- scope fallback is a runtime behavior and does not trigger an extra validation token request.
If a credential pair fails to mint a token (e.g. typo in the client secret, application disabled in LinkedIn), the save fails with the LinkedIn-reported error so you can correct the value before any data is ingested.
Troubleshooting
| Symptom | Likely cause | Resolution |
|---|---|---|
Save fails with invalid_client_id or Client authentication failed | The Client ID or Client Secret was copied incorrectly. | Re-copy both values from the LinkedIn admin console. Pay particular attention to trailing whitespace. |
Save fails with access_denied (application is not allowed to create application tokens) | The application has not been granted permission to use 2-legged OAuth on the LinkedIn side. | Contact your LinkedIn Relationship Manager or Business Development team to enable the application. |
Job runs but Users or activity steps return 403 Forbidden | The configured credentials authorize only the Content scope but the job tried to call Report endpoints (or vice versa) via the fallback. | Add a separate Report key pair (or create a single combined application with both keys checked) and re-save the integration. |
| Jobs only ingest courses but no users or completions | Only Content credentials are configured; Report-scope steps have nothing to authenticate against. | Generate a Report key pair in LinkedIn and add it to the integration. |
| Activity ingestion misses recent events | The Activity Lookback Days value is too short relative to your polling interval. | Increase Activity Lookback Days so that consecutive polling runs overlap. See the Installation tab for the trade-offs. |
Entities
The following entities are created:
| Resources | Entity _type | Entity _class |
|---|---|---|
| Account | linkedin_learning_account | Account |
| Classification | linkedin_learning_classification | Group |
| Course | linkedin_learning_course | Training |
| LearningPath | linkedin_learning_learning_path | Training |
| User | linkedin_learning_user | User |
| Video | linkedin_learning_video | Training |
Relationships
The following relationships are created:
Source Entity _type | Relationship _class | Target Entity _type |
|---|---|---|
linkedin_learning_account | HAS | linkedin_learning_classification |
linkedin_learning_account | HAS | linkedin_learning_course |
linkedin_learning_account | HAS | linkedin_learning_learning_path |
linkedin_learning_account | HAS | linkedin_learning_video |
linkedin_learning_account | HAS | linkedin_learning_user |
linkedin_learning_course | HAS | linkedin_learning_classification |
linkedin_learning_learning_path | HAS | linkedin_learning_classification |
linkedin_learning_user | ASSIGNED | linkedin_learning_course |
linkedin_learning_user | ASSIGNED | linkedin_learning_learning_path |
linkedin_learning_user | ASSIGNED | linkedin_learning_video |
linkedin_learning_video | HAS | linkedin_learning_classification |
Linkedin Learning Account
linkedin_learning_account inherits from Account
| Property | Type | Description | Specifications |
|---|---|---|---|
accountKeyRef * | string | The credential identifier (content or report client id) used to scope this account entity to its integration instance. |
Linkedin Learning Classification
linkedin_learning_classification inherits from Group
| Property | Type | Description | Specifications |
|---|---|---|---|
classificationType * | string | null | The taxonomy level of the classification (LIBRARY, SUBJECT, TOPIC, SKILL, CREDENTIALING_PROGRAM). | |
locale * | string | null | The locale of the classification name as language_country (e.g. en_US). | |
ownerName * | string | null | The localized display name of the classification owner. | |
ownerUrn * | string | null | The URN of the person or organization that owns/originally created this classification. | |
urn * | string | The opaque LinkedIn URN identifying the classification (e.g. urn:li:lyndaCategory:7220 or urn:li:skill:1234). |
Linkedin Learning Course
linkedin_learning_course inherits from Training
| Property | Type | Description | Specifications |
|---|---|---|---|
assetType * | string | The LinkedIn-reported asset type (COURSE, LEARNING_PATH, or VIDEO). | |
availability * | string | null | The availability status of the asset (AVAILABLE, RETIRED). | |
availableLanguages * | array | null | The list of language codes the asset is available in (e.g. en, de, es). | |
contributorNames * | array | null | The names of contributors involved in producing the asset (authors and publishers). | |
contributorUrns * | array | null | The URNs of contributors involved in producing the asset. | |
durationSeconds * | number | null | The duration of the asset in seconds (computed from timeToComplete). | |
isCuratedForLms * | boolean | null | Whether the asset was curated for Learning Management System consumption by an account administrator. | |
isRetired * | boolean | null | Whether the asset has been retired from the LinkedIn catalog. | |
lastUpdatedOn * | number | null | Epoch milliseconds at which the asset was last updated. | |
level * | string | null | The difficulty level of the asset (BEGINNER, INTERMEDIATE, ADVANCED). | |
primaryImageUrl * | string | null | The primary image URL used to represent the asset. | |
publishedOn * | number | null | Epoch milliseconds at which the asset was published in LinkedIn Learning. | |
retiredOn * | number | null | Epoch milliseconds at which the asset was retired, if applicable. | |
shortDescription * | string | null | The plain-text short description of the asset, localized when available. | |
ssoLaunchUrl * | string | null | The SSO launch URL of the asset, populated when an SSO connection is configured. | |
titleLocale * | string | null | The locale of the asset title as language_country (e.g. en_US). | |
urn * | string | The opaque LinkedIn URN identifying the learning asset (e.g. urn:li:lyndaCourse:563322). | |
webLaunchUrl * | string | null | The LinkedIn Learning web URL used to launch the asset for an authenticated learner. |
Linkedin Learning Learning Path
linkedin_learning_learning_path inherits from Training
| Property | Type | Description | Specifications |
|---|---|---|---|
assetType * | string | The LinkedIn-reported asset type (COURSE, LEARNING_PATH, or VIDEO). | |
availability * | string | null | The availability status of the asset (AVAILABLE, RETIRED). | |
availableLanguages * | array | null | The list of language codes the asset is available in (e.g. en, de, es). | |
contributorNames * | array | null | The names of contributors involved in producing the asset (authors and publishers). | |
contributorUrns * | array | null | The URNs of contributors involved in producing the asset. | |
durationSeconds * | number | null | The duration of the asset in seconds (computed from timeToComplete). | |
isCuratedForLms * | boolean | null | Whether the asset was curated for Learning Management System consumption by an account administrator. | |
isRetired * | boolean | null | Whether the asset has been retired from the LinkedIn catalog. | |
lastUpdatedOn * | number | null | Epoch milliseconds at which the asset was last updated. | |
level * | string | null | The difficulty level of the asset (BEGINNER, INTERMEDIATE, ADVANCED). | |
primaryImageUrl * | string | null | The primary image URL used to represent the asset. | |
publishedOn * | number | null | Epoch milliseconds at which the asset was published in LinkedIn Learning. | |
retiredOn * | number | null | Epoch milliseconds at which the asset was retired, if applicable. | |
shortDescription * | string | null | The plain-text short description of the asset, localized when available. | |
ssoLaunchUrl * | string | null | The SSO launch URL of the asset, populated when an SSO connection is configured. | |
titleLocale * | string | null | The locale of the asset title as language_country (e.g. en_US). | |
urn * | string | The opaque LinkedIn URN identifying the learning asset (e.g. urn:li:lyndaCourse:563322). | |
webLaunchUrl * | string | null | The LinkedIn Learning web URL used to launch the asset for an authenticated learner. |
Linkedin Learning User
linkedin_learning_user inherits from User
| Property | Type | Description | Specifications |
|---|---|---|---|
enterpriseGroupNames * | array | null | The enterprise group names the learner belongs to in LinkedIn Learning. | |
profileUrn * | string | null | The enterprise profile URN of the learner (e.g. urn:li:enterpriseProfile:(urn:li:enterpriseAccount:99,12345)). | |
uniqueUserId * | string | null | The customer-supplied unique identifier for the learner provisioned in LinkedIn Learning. |
Linkedin Learning Video
linkedin_learning_video inherits from Training
| Property | Type | Description | Specifications |
|---|---|---|---|
assetType * | string | The LinkedIn-reported asset type (COURSE, LEARNING_PATH, or VIDEO). | |
availability * | string | null | The availability status of the asset (AVAILABLE, RETIRED). | |
availableLanguages * | array | null | The list of language codes the asset is available in (e.g. en, de, es). | |
contributorNames * | array | null | The names of contributors involved in producing the asset (authors and publishers). | |
contributorUrns * | array | null | The URNs of contributors involved in producing the asset. | |
durationSeconds * | number | null | The duration of the asset in seconds (computed from timeToComplete). | |
isCuratedForLms * | boolean | null | Whether the asset was curated for Learning Management System consumption by an account administrator. | |
isRetired * | boolean | null | Whether the asset has been retired from the LinkedIn catalog. | |
lastUpdatedOn * | number | null | Epoch milliseconds at which the asset was last updated. | |
level * | string | null | The difficulty level of the asset (BEGINNER, INTERMEDIATE, ADVANCED). | |
primaryImageUrl * | string | null | The primary image URL used to represent the asset. | |
publishedOn * | number | null | Epoch milliseconds at which the asset was published in LinkedIn Learning. | |
retiredOn * | number | null | Epoch milliseconds at which the asset was retired, if applicable. | |
shortDescription * | string | null | The plain-text short description of the asset, localized when available. | |
ssoLaunchUrl * | string | null | The SSO launch URL of the asset, populated when an SSO connection is configured. | |
titleLocale * | string | null | The locale of the asset title as language_country (e.g. en_US). | |
urn * | string | The opaque LinkedIn URN identifying the learning asset (e.g. urn:li:lyndaCourse:563322). | |
webLaunchUrl * | string | null | The LinkedIn Learning web URL used to launch the asset for an authenticated learner. |