# Export LearnDash xAPI history: GrassBlade LRS, Tin Canny and SCORM records (2026)

https://cubite.io/blogs/export-learndash-xapi-history

**By:** Amir Tadrisi
**Updated:** 2026-11-09

Where GrassBlade and Tin Canny keep xAPI and SCORM history, and how to export and keep it.

Short answer (November 9, 2026): Export your xAPI and SCORM history before you switch anything off. GrassBlade LRS lets you read its statements out as JSON through the xAPI Statements API, and Tin Canny exports its statements as CSV from inside WordPress. Cubite LMS replaces a LearnDash plugin stack for [$290 a month or $2,900 a year](https://cubite.io/pricing), with native SCORM, xAPI and a built-in LRS. Whatever you choose, keep the export as your training record.

Cubite makes Cubite LMS and publishes this guide. Vendor and xAPI details below come from each party's own documentation and ADL's xAPI specification, read on November 9, 2026, and the export steps work whichever platform you choose.

This is the xAPI and SCORM chapter of our guide to [moving off LearnDash without losing learner data](https://cubite.io/blogs/export-learndash-courses), which covers courses, quizzes and learners. Here the subject is the tracking history your Storyline, Rise or other packaged modules sent: launches, answers, scores and completions, stored as statements in GrassBlade LRS or Tin Canny. For compliance courses, that history shows what each learner did, so it needs its own export and its own archive.

## Where xAPI and SCORM history lives on a LearnDash stack

LearnDash plays SCORM and xAPI only through an add-on: [its SCORM and xAPI documentation](https://docs.nexcess.com/software/learndash/scorm-xapi/) names GrassBlade xAPI Companion and Tin Canny by Uncanny Owl, and says xAPI also needs a learning record store (LRS), such as GrassBlade LRS. So the history sits in two or three places:

| Where it lives | What it holds | How to export it |
| --- | --- | --- |
| GrassBlade Cloud LRS (GrassBlade's servers) | Statements from xAPI and SCORM content, as JSON | Statements API; CSV or PDF report downloads |
| Self-hosted GrassBlade LRS (PHP/MySQL on your server) | The same statements, in the LRS's own tables | Statements API; report downloads; its database |
| GrassBlade xAPI Companion (WordPress plugin) | Completions passed back to LearnDash: its grassblade_completions table and LearnDash's activity table | WordPress database export |
| Tin Canny Reporting for LearnDash (WordPress plugin) | SCORM and xAPI statements: user, module, activity, result, timestamp | CSV from the Tin Can Report and the xAPI Quiz Report; WordPress database export |
| LearnDash core (WordPress) | Course progress and quiz results; activity table wp_learndash_user_activity | Course Data and Quiz Data CSV reports; database export |

Three details decide how you export. GrassBlade LRS is not a WordPress plugin ([GrassBlade's own words](https://www.nextsoftwaresolutions.com/kb/difference-between-grassblade-lrs-and-grassblade-xapi-companion/)): the Cloud LRS keeps statement history on GrassBlade's servers, outside your WordPress database, and a self-hosted LRS keeps its tables in whichever MySQL database you gave it at install; GrassBlade's install guide prefers the WordPress database login and table prefix, so check where yours went. GrassBlade xAPI Companion writes completions back into WordPress, so LearnDash knows who passed while the LRS holds what they did. And Tin Canny keeps everything in WordPress, in what Uncanny Owl calls a learning record store native to WordPress.

## Route A: export every statement through the xAPI Statements API

The Statements API is the part of the xAPI specification an LRS uses to receive and return statements. ADL publishes it on [GitHub](https://github.com/adlnet/xAPI-Spec/blob/master/xAPI-Communication.md) as version 1.0.3, and its repository notes that xAPI 2.0 is now the current version. A GET request to the statements resource returns a StatementResult: statements, plus a "more" link while more remain. It works the same with any LRS that implements the specification, GrassBlade LRS included.

### Step 1: create read credentials in GrassBlade LRS

1. Sign in to the GrassBlade LRS dashboard as an admin manager (a self-hosted LRS usually sits at yourdomain.com/grassblade-lrs).
2. Open My Profile, top right, and click Add New Basic AuthToken.
3. Copy the API User, the API Password and the Endpoint shown under Authentication Details ([GrassBlade's connection guide](https://www.nextsoftwaresolutions.com/kb/connect-grassblade-lrs-with-grassblade-xapi-companion/) shows the screens).
4. Send them as HTTP Basic authentication, with an X-Experience-API-Version header (for example 1.0.3) on every request.

Treat the token like a password: [GrassBlade's documentation](https://www.nextsoftwaresolutions.com/kb/secure-tokens-a-critical-data-safety-feature/) says Basic Authentication details are used to read and write LRS data, in most cases with unrestricted access, and that anyone holding them can download all the LRS data. Use it only for the export, and delete the token when the export is done.

### Step 2: page through every statement

Request the Endpoint with statements added to the end. The specification's query parameters do the rest:

- limit: the most statements per response, for example 500. The LRS may return fewer, and 0 asks for its maximum.
- ascending=true: oldest first by stored time, which makes a long export easy to resume. The default is newest first.
- format=exact, the default: statements exactly as the LRS received them.
- since and until: slice the export by the time the LRS stored each statement (not the module's timestamp), for example by year.
- agent, verb and activity: one learner, verb or module, for spot checks.

Each response has a "more" property. While it is not empty, it holds a relative link (path and query, no scheme, host or port): join it to your Endpoint's scheme, host and port (not its path), and request it next. The specification keeps that link valid for at least 24 hours. An empty "more" means you have everything. Save each response as its own untouched JSON file, and note the X-Experience-API-Consistent-Through header, the time up to which the LRS says its statements are available.

Two more rules matter for a record. A list query never returns voided statements (cancelled by a later voiding statement), though it does return the voiding statements, so fetch a voided one by its voidedStatementId if you need it. And attachments come back only with attachments=true. Then total the statements across your files and compare the total with the LRS's own reports for the same period.

## Route B: the CSV exports each vendor documents

Both add-ons document a CSV download. A CSV flattens each statement into a row, so it is not the raw record, but it is the file a client or an auditor can open.

### GrassBlade LRS: download the Activity Stream

1. Open a report page such as Reports > Activity Stream.
2. Click the filter icon and set the filters. To include quiz answers, turn on Include Sub Activities.
3. Click the download icon, enter the download limit (the number of recent rows to include), and choose CSV and All Columns.
4. Click download. Earlier files stay listed on the Download History page.

Two settings matter, per [GrassBlade's download guide](https://www.nextsoftwaresolutions.com/kb/download-filtered-reports/) and its settings page. The Download Limit sets how many rows a download holds, so check it or split the export by date. Trash Report Files After deletes downloaded files from the server after the number of days you set, so move each file into your archive at once.

### Tin Canny: export the Tin Can Report and the xAPI Quiz Report

Tin Canny Reporting for LearnDash records interactions from xAPI, SCORM 1.2 and SCORM 2004 modules added with its uploader. Its [Tin Can Report](https://www.uncannyowl.com/knowledge-base/tin-can-report/) lists each statement with group, user, course or module, target, action, result, success and date, and its xAPI Quiz Report holds question-level responses. Both export the filtered results with an Export to CSV button, and since version 4.1.2 the CSV has a user ID column. Use the date filters to split a large export.

Export before any cleanup. Tin Canny's Reset Data setting can purge statements, and since version 5.0 (May 8, 2025) an option removes all Tin Canny data when the plugin is deleted, according to its [changelog](https://www.uncannyowl.com/knowledge-base/tin-canny-learndash-reporting-changelog/). Check that option before you delete the plugin.

## Route C: a full database export as the fallback

A database export keeps every row the reports leave out. It is hard to read without the software that wrote it, so keep it beside the JSON and CSV files, not instead of them.

- The WordPress database holds Tin Canny's statements, LearnDash's progress and activity tables, and the completions GrassBlade wrote back. Take it with your host's backup tool or mysqldump.
- A self-hosted GrassBlade LRS lives in the MySQL database you set at install, and GrassBlade's guide to moving the LRS starts with copying that database; if it shares the WordPress database, that export carries it. GrassBlade's knowledge base lists its learner-data tables, such as wp_gb_all_statements with the default wp_ prefix, in [an article last updated December 15, 2015](https://www.nextsoftwaresolutions.com/kb/how-to-clear-learner-activity-data-from-lrs-database/), so check the names in yours.
- GrassBlade Cloud LRS runs on GrassBlade's servers, with the database managed for you, so routes A and B are your export. Run them while the subscription and the token are active.

## Keep the export as your compliance record

An export becomes a record when you can show it is complete and unchanged. The rules and contracts that apply to your training decide what you keep and for how long, and you stay responsible for meeting them. A layout that makes both easy to show:

1. Raw JSON: one file per API response, as returned. The specification treats statements as immutable, so never edit these files.
2. A flat CSV built from the JSON, one row per statement: who, what, when and score (columns below).
3. The vendor CSVs from route B, plus LearnDash's Course Data and Quiz Data reports, which the [move-off guide](https://cubite.io/blogs/export-learndash-courses) covers.
4. A manifest: the Endpoint, the export date, the Consistent-Through value, and the statement count of each file and in total.
5. SHA-256 checksums of every file (shasum -a 256 on a Mac, sha256sum on Linux, Get-FileHash in PowerShell), checked again after every copy.
6. The database export, encrypted, and restored only into a private staging copy when you need to read it.

| CSV column | Statement property (xAPI 1.0.3) |
| --- | --- |
| statement_id | id |
| learner (who) | actor.mbox (mailto: plus an email address) or actor.account.name |
| verb (what) | verb.id and verb.display, for example answered or passed |
| activity | object.id and object.definition.name: the module, slide or question |
| score_scaled, score_raw | result.score.scaled (from -1 to 1) and result.score.raw |
| success, completion | result.success and result.completion |
| timestamp (when) | timestamp: when it happened, as the module reported it |
| stored | stored: when the LRS recorded it |
| registration | context.registration, when the content sends one |

Store two copies where your organization controls access, for example a restricted, read-only folder and a copy in a separate account or offline, and treat them as personal data: the actor field identifies each learner, often by email address. Keep them for the longest retention period that applies; [LearnDash for compliance training](https://cubite.io/blogs/learndash-compliance-training) covers retention rules. Cancel the old LRS, purge data or delete plugins only after the counts match and the checksums verify.

If you would rather keep the old history queryable, you can also keep GrassBlade LRS after you leave LearnDash: it is not a WordPress plugin, and GrassBlade says any source that can send data to an LRS can send it to GrassBlade LRS. The file archive is still the copy you control.

## What a move to Cubite LMS carries

LearnDash's WordPress export (WXR) carries course content only; learners, enrollments, progress, quiz scores and certificates live in the database, so a move to a hosted LMS needs a database export. Cubite moves the whole LearnDash site, including learners, enrollments, progress, quiz attempts and groups, with earned certificates re-issued, as a migration it runs for you from that database export. The migration is included at no extra cost with every paid Cubite LMS plan: Growth at $290 a month or $2,900 a year, Perpetual, or Enterprise.

Cubite works from a copy, so the live LearnDash site is not touched, and you review the record counts and sign off before launch. WordPress passwords do not move: learners sign in from an invite or an emailed sign-in link. Certificates are re-issued with the original completion date.

Raw statement history is not one of the listed migration items, so keep your export: it stays your record of what learners did in the old modules. [What transfers when you leave LearnDash](https://cubite.io/blogs/what-transfers-when-you-leave-learndash) compares what different platforms import from LearnDash, and the [LearnDash migration assessment](https://cubite.io/learndash-migration) maps what your site holds.

On Cubite LMS, SCORM 1.2, SCORM 2004 and xAPI packages (for example Storyline or Rise exports) are uploaded as zip files of up to 500 MB and play natively; xAPI statements go to Cubite's built-in LRS, and SCORM progress is recorded per learner. That LRS stores the statements sent by packages played inside Cubite; it does not import statements from other systems and has no public Statements API for other tools. See the [SCORM, xAPI and built-in LRS page](https://cubite.io/scorm-xapi-lms).

Site admins export learner records as CSV files (roster, enrollments, progress, gradebook and certificates), and a full export is available on request (section 6 of the [terms](https://cubite.io/terms)). When a learner leaves a site or closes their account, their enrollments, progress and certificates are kept for the site's retention period, 6 years by default and configurable per site. Comparing the two add-ons first? See [Tin Canny vs GrassBlade](https://cubite.io/blogs/tin-canny-vs-grassblade).

Vendor details were read in each vendor's own documentation, and xAPI details in ADL's specification (version 1.0.3), on November 9, 2026. Menus and settings change between versions, so check yours before you export.

## Exporting LearnDash xAPI history: questions

### How do I export statements from GrassBlade LRS?

Create a Basic AuthToken (My Profile, then Add New Basic AuthToken), send GET requests to the Endpoint's statements resource with that API User and API Password, follow the more link until it comes back empty, and save each response as JSON. For a spreadsheet, download Reports > Activity Stream as CSV with Include Sub Activities on.

### Can I export Tin Canny data?

Yes, as CSV: the Tin Can Report and the xAPI Quiz Report each export their filtered results, with a user ID column. The statements live inside your WordPress site, so a WordPress database export carries every row. Export before you purge statements or delete the plugin, since Tin Canny has an option to remove all its data on deletion.

### What is the xAPI Statements API?

The part of the xAPI specification an LRS uses to receive and return statements. A GET request to the statements resource returns a StatementResult, statements plus a more link for the next page, filtered by since, until, agent, verb or activity if you ask.

### Does LearnDash's own export include xAPI or SCORM history?

LearnDash's Import/Export lists LearnDash's own data types, from courses and quizzes to users, and imports into another LearnDash site. SCORM and xAPI tracking sits with the add-on that played the module, GrassBlade LRS or Tin Canny, so export it there. GrassBlade does write completions back to LearnDash's activity table.

### How long should I keep LearnDash training records after I move?

For the longest retention period that applies to the training, set by the rules and contracts you work under; our LearnDash for compliance training guide covers retention rules. On Cubite LMS, the records of a learner who leaves a site are kept for the site's retention period, 6 years by default and configurable per site.

### What does a move to Cubite LMS carry from LearnDash?

LearnDash's WordPress export (WXR) carries course content only; learners, enrollments, progress, quiz scores and certificates live in the database, so a move to a hosted LMS needs a database export. Cubite moves the whole LearnDash site, including learners, enrollments, progress, quiz attempts and groups, with earned certificates re-issued, as a migration it runs for you from that database export. The migration is included at no extra cost with every paid Cubite LMS plan: Growth at $290 a month or $2,900 a year, Perpetual, or Enterprise. Raw statement history is not one of the listed migration items, so keep your export.

## Leaving LearnDash with xAPI history?

Book a 30-minute call about your GrassBlade or Tin Canny export and what the migration carries.

[Book a call](https://cubite.io/go/book?src=xapi-history)
