This article was co-written by OpenCraft team member Adolfo Brandes and Daniel Seaton, Sr. Learning Systems Designer at MIT.

In this article, we’ll describe how problems, videos, and pages from Open edX courses can be reused on the Canvas LMS via a new LTI implementation in Libraries v2, a feature recently developed by OpenCraft for MIT Open Learning. This project builds upon a wider effort commissioned by edX to enhance LTI compliance (1,2) and build more flexible and robust content libraries (1) for the Open edX platform.

Before getting into the details, let’s dive a little on why this was done in the first place.

The Problem With Exporting Content

If you’ve ever authored courseware, you know how difficult it is to produce quality content.  And if you spend a lot of time doing it, chances are you’ll end up with an extensive library on a particular platform, such as Open edX courseware.  What happens, though, when you want to reuse that content elsewhere?  Few people would relish rewriting everything from scratch!

There are different ways a platform can allow content to be reused.  The most common is by letting data be exported.  This has been possible in Open edX since its inception: one can export courseware using the Open Learning XML format.  But while it’s straightforward to import the resulting tarball into a separate Open edX instance, bringing this content into another platform altogether presents a series of challenges:

  • Conversion: Before the content can be reused, it must be converted into a format the target platform understands.  Depending on the data, doing this can be anything from easy to unfeasible.
  • Version control: Even after conversion and import, the fact remains that if the author wants to change the content, they’ll have to do it twice: once in the original platform and again in the second one.

Luckily, an organization called the IMS Global Learning Consortium came up with LTI, which aims to solve the issues above.  LTI is short for “Learning Tools Interoperability”: as long as both platforms support it, you can simply point the target platform to the source, and voilà!  The learner will be able to interact with your painstakingly created content transparently, no import necessary.  Best of all, if you make changes to the original content, those changes will be reflected anywhere you have reused it.

Open edX has been able to act as an LTI provider for a long time, and Canvas has correspondingly been able to consume from Open edX courses on a block-by-block basis.  What else was needed, then?  

Courses Make Poor Libraries

Here’s the thing.  Reusing content originally written as part of a regular course is clunky at best.  There are difficulties with content structured in this manner, particularly when it comes to Open edX:

  • Large courses often contain content on disparate topics, with no tooling for authors to think about grouping for the sake of later reuse.
  • Searching for content inside Open edX is not ideal.  It’s hard to click-through and find all videos on black holes, for instance, if they’re distributed across different sections in a course, or even worse, across multiple courses.

It is for these and other reasons that Content Libraries development began in 2019.  (OpenCraft CTO Braden MacDonald gives a great overview of the motivation behind this push, which includes the Blockstore backend, in this video.)  With better search features and making grouping of related content much easier, they’re designed to support content reuse within Open edX courses.

The catch?  As of early 2020, Open edX Content Libraries did not yet support any kind of LTI integration.  While it was possible to reuse library content from within an Open edX instance, you couldn’t do so externally.

Enter MIT, Content Libraries, and LTI

MIT, by any measure, is a heavy user of Open edX, maintaining an instance solely for on-campus teaching and learning. The instance has hosted over 200 unique courses for MIT students, leading to more than 35,000 unique problems, 15,000 unique videos, and 23,000 pages. The on-campus instance of Open edX is not the primary LMS at MIT, but exists as an optional system for creating enhanced, blended learning experiences.

In Fall 2021, the Canvas LMS was introduced at MIT to replace a homegrown, legacy system that did not offer the features of a modern LMS. Given the extensive library of rich content on MIT’s on-campus Open edX instance, the introduction of Canvas created new opportunities to think strategically about content integrations between the two platforms. MIT approached OpenCraft about their recent work on Content Libraries with Blockstore and began formulating a starting point to address broader ambitions related to content interoperability.

In short: MIT needed LTI for Content Libraries.  So, over a few months at the end of 2021, OpenCraft built not only a way for Canvas to use LTI to integrate Content Libraries, but a way for authors to import content from preexisting courses into Content Libraries. The current implementation allows single xblocks (e.g., a problem, video, or page) to be reused via LTI.

Trying It Out

Instead of just describing the new features, let’s show you how to actually use them with the Open edX and Canvas development environments. (The steps below require you to set up a local Open edX devstack and a local Canvas development environment.)

Set up the base development environments

To start, set up your Open edX devstack with the Libraries v2 frontend and Blockstore backend, as outlined in Library Authoring project README.  Then proceed to set up a Canvas development environment using the automated setup described in its Quick Start guide.  We won’t walk through individual steps in setting these environments up, as that would be beyond the scope of this post.  Worry not, though!  The corresponding setup procedures are well documented in each project.

From this point on we’ll assume you were able to set them up successfully, including being able to access:

  • The Open edX LMS at,
  • Studio at,
  • The Libraries v2 authoring interface at,
  • Canvas at http://canvas.docker.

Preparing Canvas

Continue by logging into your local development instance of Canvas as an administrator, and creating a Developer Key.  You can do so from the Admin > Account panel, as shown below:

To start creating the key, click on + Developer Key, then + LTI Key, like so:

On the “method” drop-down, select “Paste JSON”, and copy/paste the following into the text box (you could fill fields individually, but this makes it easier!):

    "title": "edX Content Library",
    "scopes": [],
    "extensions": [
            "platform": "",
            "settings": {
                "platform": "",
                "placements": [
                        "placement": "assignment_selection",
                        "message_type": "LtiDeepLinkingRequest"
            "privacy_level": "anonymous"
    "public_jwk": {},
    "description": "edX Content Library",
    "custom_fields": {},
    "public_jwk_url": "",
    "target_link_uri": "",
    "oidc_initiation_url": ""

Note: the last three URLs point to Studio on your local Open edX devstack.

Give the key a name, such as “Open edX Tool”, and save it.  Then immediately enable it by clicking on its ON button as shown below, and copy the client ID (“10000000000001”, here) to your clipboard.

Now we’ll add an “App”.  Go to Site Admin > Settings, and on the Apps tab, click on the + App button.  Choose the “By Client ID” configuration type, and paste the client ID from the key you created above:

After clicking Submit, confirm you want to install the app by clicking on Install.  You should now see an “edX Content Library” app in the list of external apps.

Click on the app’s configuration icon, then on Deployment Id.  You’ll need the identifier (here, “1:8865aa05b4b79b64a91a86042e43af5ea8ae79eb”) when setting up Open edX, so copy it to the clipboard.

Preparing Open edX

Start by enabling the content libraries LTI tool for Studio.  You’ll need to edit the Features setting from the Studio container itself:

cd devstack
make studio-shell
vim /edx/etc/studio.yml

Save the file, exit, and restart Studio via:

make studio-restart

Next, you’ll need to pre-generate a JSON Web Token keypair as a means for Open edX and Canvas to trust each other.  An easy way to do it from the command line using SSH and openssl is:

ssh-keygen -t rsa -b 4096 -m PEM -f jwt.key
openssl rsa -in jwt.key -pubout -outform PEM -out
cat jwt.key

Note the contents of each file, as you’ll need them shortly.

Now log into Studio as an administrator, then proceed to the Django admin interface at the following address:


Click + Add on the “Lti 1.3 tool keys” entry, give it an arbitrary name, and paste the corresponding keys you created above.  In other words, under “Private key”, paste the contents of jwt.key, and under “Public key”, paste, like so:

Once the key is saved, go to the list of LTI tools at:

Click on ADD LTI 1.3 TOOL on the top right, and fill the fields with the corresponding information:

  • Title: Canvas Tool
  • Is active: yes
  • Issuer:
  • Client ID: the identifier of the Canvas Developer key you created earlier.  In this example: 10000000000001
  • Auth login URL: http://canvas.docker/api/lti/authorize_redirect
  • Auth token URL: http://canvas.docker/login/oauth2/token
  • Key set URL: http://canvas.docker/api/lti/security/jwks
  • Took key: select the key you created in the previous step
  • Deployment IDs: the identifier of the Canvas App deployment created earlier, formatted as a JSON list.  In this example: [“1:8865aa05b4b79b64a91a86042e43af5ea8ae79eb”]

That’s it!  When you click save, Open edX Content Libraries and Canvas will be set up to communicate with each other via LTI.

Creating a Library from Scratch

What’s left to do is to actually create a content library with some content in Open edX, and to finally consume it in the Canvas instance.

Start at the Open edX library authoring frontend, which in the devstack setup is located at:


Click on New Library, filling the fields out as you see fit: the library details are arbitrary.  Just make a note of them for later!  For instance:

After submitting, add a “Poll” block by clicking on the Advanced button, then on Poll.  (For the purposes of testing LTI integration, you don’t need to customize it, but feel free to do so by clicking on the block’s Edit button.)  The block should be visible in the library you created, like so:

Next, you’ll need to explicitly allow this library to be shared via LTI.  For now, the only way to do so is via Studio’s admin interface, at:

Click on the library’s ID (in this case, “library01”) to edit its metadata.   Under “Authorized LTI configs”, simply click on the first “LtiTool object” (which refers to the LTI configuration that points to Canvas you created earlier) so that it remains selected:

Click Save, then go back to the library authoring frontend and the library you created (here,, and refresh the page.  You should now see a “Copy LTI URL” button alongside the poll block you just created.

The presence of the Copy LTI URL button is confirmation that this library is accessible via LTI.  Click on it: doing this will copy this block’s LTI integration URL to your clipboard.

Import from an Existing Course

Instead of creating blocks from scratch, you can also import them from a preexisting course into a library.  To do so, go to the library’s Settings menu, and click on import:

Next, click on Show Importable Courses, then import the Demonstration Course by clicking on its Import Course button.  After a few seconds, the import should be completed:

If you then go back to the library page, you should see a list of all the imported blocks, all of which could also be used via LTI:

Consuming Open edX content from Canvas

Now, go back to the Canvas Dashboard and click on Start New Course.  Give the course any name you like, then from its home page click on Assignments, then + Assignment to create a new (you guessed it!) assignment.  Its name is also arbitrary (we’re calling ours “Open edX Poll”), but under “Submission Type”, choose “External Tool”.  And for External Tool URL, paste the LTI URL that’s on your clipboard.  In our case, it looks like this:

Click on save, and… That’s it!  Your Canvas learners should now be able to interact with the poll block from within a Canvas course, just as if they were using it inside Open edX.  And yes, this includes grading!

Note: LTI urls can also be used in an <iframe> in any Canvas Page, which is great for embedding videos, pages, and other non-graded content. An easy way to try this is by including an LTI url, for a video or page, within the content editor for an assignment. You can include an <iframe> with an LTI url anywhere you can access the Rich Content Editor in Canvas. 

The Future

It’s still early days for Open edX Content Libraries, but the fact that Library items can now be used via LTI integration opens up a realm of possibilities.  Because libraries are unbound from the traditional courseware structure, they allow more effective content reuse.  And because their content can be accessed programmatically, it can be used in all kinds of interesting ways, for instance, for adaptive learning. In addition, Libraries offer an easier entry point to the vast array of Open edX problem types. Allowing instructors to start their authoring journey from a Library might make for an easier introduction to the power of the Open edX platform.

If you’d like to know more, let us know!

Header image: “Canvas Skies” by Nichole Renee is licensed under CC BY 2.0