> For the complete documentation index, see [llms.txt](https://enterprise-docs.datacamp.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://enterprise-docs.datacamp.com/integrating-our-data-into-your-tools-via-data-connector-2.0/explore-the-data-model/fact-tables.md).

# Fact tables

Fact tables store quantitative information (measurements/metrics) about events (facts) based on users' activity on DataCamp.

* The fact tables available are:
  * [**fact\_learn\_events**](#fact_learn_events)
  * [**fact\_certification\_events**](#fact_certification_events)
  * [**fact\_datalab\_events**](#fact_datalab_events)
  * [**fact\_permission\_events**](#fact_permission_events)
  * [**fact\_ai\_insights\_disclosures**](#fact_ai_insights_disclosures)

Events in the fact tables only include activity that occurred **while the user was part of the group**. This means that any events from before the user joined or after they left the group are not included in these tables. As a result, the recorded activity reflects only the period during which the user was associated with the group, rather than their complete history on the platform. This is an important distinction to keep in mind when aggregating metrics using fact tables, as the totals may not represent a user’s full learning journey on DataCamp.

### fact\_learn\_events

This table captures learning events and user interactions on the platform.

These are the event types in this table:

* Starts and completion events, arguably the most common, reflect content starts and/or completions:

  * `assessment_started` and `assessment_completed`
  * `course_started` and `course_completed`
  * `chapter_started` and `chapter_completed`
  * `exercise_completed`
  * `practice_completed`
  * `project_started` and `project_completed`
  * `track_started` and `track_completed`
  * `assignment_completed` and `assignment_completed_late`– The assignment was completed on time (on or before the due date) or late (after the due date).
  * `assignment_assigned` – The assignment was issued to the assignee.
  * `assignment_missed` – The assignment was not completed before the due date.
  * `assignment_unassigned` – The assignment was deleted after the creation.

  When an assignment is missed, an `assignment_missed` event is logged. If the user later completes the assignment after the due date, an `assignment_completed_late` event is also recorded. In this case, both the missed and late completion events are preserved.

{% hint style="info" %}
In assignment events, the `duration_engaged` and `xp_earned` columns remain NULL. Engagement time and XP are recorded through the learner’s interactions with the assigned content, such as `course_engagement` and `assessment_engaged`.
{% endhint %}

* Engagement events that reflect user interaction with particular content, such as time spent and XP earned:
  * `assessment_engaged`
  * `course_engagement`
  * `practice_engagement`
  * `project_engagement`
* One-off XP events:
  * `alpa_onboarding`
  * `b2b_onboarding_xp_boost`

{% hint style="info" %}
We stopped awarding `b2b_onboarding_xp_boost` in October 2024
{% endhint %}

Most fact events are associated with a specific content item via the `content_id` column, which can be used to perform a join with the `dim_content` table. For track events, the `track_version_id` column is used (and the `content_id` column will be empty), which can be used to join with the `dim_track` table. Assignment events use `assignment_id` to join with `dim_assignment` and retrieve assignment details.

Every fact event has a `occurred_at` timestamp that determines when the event happened.

Additionally, content-specific fields will have data when the event is related to specific content types. For example, `assessment_score` will contain the assessment score for `assessment_completed` events.

{% hint style="info" %}
For course-related and chapter-related events (e.g., `course_started`, `course_completed`, `chapter_started`, `chapter_completed`, `course_engagement`), the `course_variant_id` column identifies which variant the user interacted with. A user can start and complete both the Datacamp and AI Tutor variant of the same course, resulting in separate events for each variant. Use `course_variant_id` to filter or group by variant. Join with `dim_course_variant` for variant metadata.
{% endhint %}

<table><thead><tr><th width="374">Field</th><th>Description</th></tr></thead><tbody><tr><td>user_id</td><td>The unique user identifier</td></tr><tr><td>date_id</td><td>The date identifier (YYYYMMDD)</td></tr><tr><td>content_id</td><td>The unique content identifier</td></tr><tr><td>course_variant_id</td><td>The course variant identifier. <code>1</code> = datacamp, <code>2</code> = ai-tutor. Populated for course and chapter events. Can be joined with <code>dim_course_variant</code> for variant details.</td></tr><tr><td>track_version_id</td><td>The unique track identifier</td></tr><tr><td>assignment_id</td><td>The unique assignment identifier</td></tr><tr><td>event_name</td><td>The name of the event</td></tr><tr><td>occurred_at</td><td>The timestamp when the event took place (UTC)</td></tr><tr><td>xp_earned</td><td>The XP earned on the event</td></tr><tr><td>duration_engaged</td><td>The time (in seconds) the user spent engaged with the particular content item</td></tr><tr><td>assessment_score</td><td>The assessment score (0-200)</td></tr><tr><td>assessment_percentile</td><td>The percentile that corresponds to the assessment score</td></tr><tr><td>assessment_knowledge_level</td><td>The skill level (Novice, Lower Intermediate, Upper Intermediate, Lower Advanced, Upper Advanced) that correlates to the assessment score</td></tr><tr><td>course_is_skipped</td><td>Determines whether the course was skipped. Only used for <code>course_completed</code> events.</td></tr></tbody></table>

{% hint style="warning" %}
Not all events in the fact learn events table will have a corresponding content item in `dim_content`. This is due to a limitation in our system, where some content items are hard deleted on our end. Despite this, we still include events related to these deleted content items in the fact table because they represent valuable user activity—users gained XP and spent time engaging with the content. Even if the content reference is missing, these events provide meaningful insights into user learning behavior and should not be excluded from reporting.\
\
Please check the [Domain Gotchas](/integrating-our-data-into-your-tools-via-data-connector-2.0/domain-gotchas.md) section for more details.
{% endhint %}

### fact\_certification\_events

This table captures ordinary Certification events and the separate CPE skill-verification lifecycle.

These are the event types in this table:

* Certification milestone events
  * `certification_registered`
  * `certification_withdrawn`
  * `certification_failed`
  * `certification_expired`
  * `certification_granted`
* Certification component events
  * Attempts
    * `certification_attempt_expired`
    * `certification_out_of_attempts`
  * Case Studies
    * `certification_case_study_registered`
    * `certification_case_study_presentation_submitted`
    * `certification_case_study_graded`
    * `certification_case_study_failed`
    * `certification_case_study_passed`
  * Project
    * `certification_project_registered`
    * `certification_project_passed`
    * `certification_project_failed`
    * `certification_project_expired`
  * Skill Assessment
    * `certification_skill_assessment_registered`
    * `certification_skill_assessment_failed`
    * `certification_skill_assessment_passed`
* CPE skill-verification events
  * `skill_verification_started` — The learner started the CPE assessment.
  * `skill_verification_completed` — The learner completed the CPE assessment. Its timestamp is the reporting-period anchor for CPE activity.
  * `skill_verification_granted` — The learner met the assessment and associated-course requirements and was awarded the certificate and CPE credits.
  * `skill_verification_failed` — The CPE assessment attempt failed.

Every event is tied to a specific certification attempt. Use `certification_id` to join with `dim_certification` for certification metadata. Use `attempt_id` to stitch events that belong to the same attempt — the same `attempt_id` value is shared across the parent certification milestone events and all three component families (project, skill assessment, case study), so a full per-attempt funnel can be reconstructed by ordering events by `occurred_at` within an `attempt_id`.

Each component family emits a `_registered` event for every attempt the user starts, plus the corresponding outcome events (`_passed`, `_failed`, and where applicable `_expired` or `_graded`). This gives complete funnel coverage per attempt: which component the user started, which they finished, and how each outcome was reached.

CPE attempts use the same `certification_id` and `attempt_id` join pattern, but their lifecycle is independent from ordinary Certification events. The assessment and associated course can be completed in either order. Credits are populated only when the `skill_verification_granted` event is emitted.

| Field                      | Description                                                                                                                                                               |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| user\_id                   | The unique user identifier                                                                                                                                                |
| date\_id                   | The date identifier (YYYYMMDD)                                                                                                                                            |
| certification\_id          | The unique certification or CPE skill-verification identifier                                                                                                             |
| event\_name                | The name of the event                                                                                                                                                     |
| xp\_earned                 | The XP earned on the event                                                                                                                                                |
| occurred\_at               | The timestamp when the event took place (UTC)                                                                                                                             |
| attempt\_id                | The unique certification or CPE skill-verification attempt identifier                                                                                                     |
| cpe\_exam\_reported\_score | The reported CPE assessment score. Populated on completed events, or on a failed event when no completion event exists; otherwise null                                    |
| is\_cpe\_course\_completed | Whether the learner completed the associated course at any time                                                                                                           |
| cpe\_course\_completed\_at | The first completion timestamp for the course associated with the CPE skill verification, populated only when completion occurred during group membership; otherwise null |
| cpe\_credits\_obtained     | The credits awarded on a `skill_verification_granted` event; otherwise null                                                                                               |

{% hint style="info" %}
Use `certification_*` events for ordinary Certification reporting and `skill_verification_*` events for CPE reporting. The two event families should not be combined into one Certification metric.
{% endhint %}

#### Filtering CPE in `fact_certification_events`

Because `fact_certification_events` holds events for both ordinary Certifications and CPE skill verifications, you can separate them either by event name or by joining with `dim_certification`:

* **Select only CPE events**: Filter for event names starting with `skill_verification_` (`skill_verification_started`, `skill_verification_completed`, `skill_verification_granted`, `skill_verification_failed`), or join with `dim_certification` and filter for `certification_type = 'cpe'`.
* **Select only ordinary Certification events (excluding CPE)**: Filter for event names starting with `certification_` (or exclude event names starting with `skill_verification_`), or join with `dim_certification` and filter for `certification_type != 'cpe'`.

### fact\_datalab\_events

This table captures events related to interactions within DataLab on the platform.

These are the event types in this table:

* Workbook creation:
  * `workspace_created`
* Engagement events that reflect interactions with DataLab workbooks:
  * `workspace_publication_viewed`
  * `workspace_viewed`
    * When a user spends time viewing a DataLab workbook
  * `workspace_visited`
    * When a user spends time either viewing or editing a workbook

{% hint style="warning" %}
Please note that the workspace\_viewed events are a subset of workspace\_visited events. Only one of the two events should be used when calculating time spent on DataLab workbooks.
{% endhint %}

Most fact events are associated with a specific DataLab workbook via the `workbook_id` column. The `workbook_id` is used in the URL for the workbook. DataLab workbooks have the following URLs: `https://www.datacamp.com/datalab/w/workbook_id`.

Every fact event has a `occurred_at` timestamp that determines when the event happened.

| Field             | Description                                                           |
| ----------------- | --------------------------------------------------------------------- |
| user\_id          | The unique user identifier                                            |
| date\_id          | The date identifier (YYYYMMDD)                                        |
| workbook\_id      | The unique workbook identifier                                        |
| event\_name       | The name of the event                                                 |
| occurred\_at      | The timestamp when the event took place (UTC)                         |
| duration\_engaged | The time (in seconds) when the user was engaged with the workbook     |
| workbook\_source  | Source of the workbook (e.g., dataset template, course continuation). |
| workbook\_class   | Class of the workbook (e.g., notebook, exploration).                  |

### fact\_permission\_events

This fact table captures permission, license and invite related events across the platform.

**Event types in this table include:**

* **Subscription:** `subscription_started`, `subscription_ended` (with related subscription metadata, e.g., license counts).
* **License:** `user_license_allocated`, `user_license_revoked`.
* **Invites:** `invite_sent`, `invite_claimed`, `invite_withdrawn`.

Each event is one row and carries an `occurred_at` timestamp indicating when the event happened.

| Field                   | Description                                                                |
| ----------------------- | -------------------------------------------------------------------------- |
| team\_id                | The unique team identifier if the event is associated with a specific team |
| user\_id                | The unique user identifier if the event is associated with a specific user |
| email                   | The email of the person invited                                            |
| date\_id                | The date identifier (YYYYMMDD)                                             |
| event\_name             | The name of the event                                                      |
| occurred\_at            | The timestamp when the event took place (UTC)                              |
| invite\_id              | The unique invite identifier                                               |
| is\_active              | Indicates whether the subscription or the license is currently active      |
| product                 | Product the event is associated to, e.g. 'learn' or 'workspace'            |
| license                 | License the event is associated to, e.g. 'enterprise', 'teams', etc...     |
| slug                    | The product slug, e.g. 'learn.enterprise'                                  |
| nb\_licenses\_purchased | The number of licenses purchased.                                          |

### fact\_ai\_insights\_disclosures

This table captures non-sensitive topics and AI-tool mentions during AI Tutor conversations.

For tool signals, each row is the first disclosure for a learner and displayed tool label while the learner was part of the group. For topic signals, each row is the first disclosure for a learner, AI Tutor step, and topic while the learner was part of the group.

| Field              | Description                                                                                                       |
| ------------------ | ----------------------------------------------------------------------------------------------------------------- |
| discloser\_id      | The hashed identifier of the user                                                                                 |
| thread\_id         | The AI Tutor conversation identifier                                                                              |
| slice\_id          | The hashed identifier of the conversation slice the signal came from                                              |
| signal\_type       | The disclosure type: `topic` for a learner disclosure or `tool` for an AI-tool mention                            |
| step               | The AI Tutor step associated with the disclosure: `task`, `challenge`, `refinement need`, or `profiling`          |
| category           | The assigned classification: a topic cluster for topic signals or a canonical tool label for tool signals         |
| detail             | The extracted disclosure for topic signals or the raw tool mention for tool signals                               |
| is\_internal\_tool | For tool signals, whether the mentioned tool is a company-internal bespoke tool. This is `null` for topic signals |
| occurred\_at       | The timestamp of the conversation's first message (UTC), used to scope the disclosure to group membership         |
| generated\_at      | The timestamp when the disclosure signal was generated (UTC)                                                      |
