Skip navigation
All Places > Canvas Developers > Blog > 2018 > November

Templates are Awesome!  They help create a solid launching point for creating quality courses.

There are a couple of different ways to put a template in a new course shell.

  1. Importing a template course from Commons
  2. Using the Blueprint feature
  3. Copying another course which you have designated as a 'Template'.


Depending on the needs and workflow of your institution any one of these can work very well. This blog will focus on the third method listed "Copying another course which you have designated as a Template."



As a Remote Canvas Admin, I have been asked to apply a course template to all newly created courses for an institution that I serve. This was a daily task, so I decided to automate it using Google Sheets / App Script.  Word got out around the office about my tool and I've had a couple of requests for it, so I decided to make it generic for any institution and share it here in the Community. I chose Google Sheets because it is easily shareable with anyone, uses mostly JavaScript and offers a UI that makes manipulating data more human readable.



This tool is a Google Sheet that uses the App Script language which is mostly JavaScript.  Once it is configured, just click the 'Canvas' menu, then 'Apply Template to Unchanged & New Courses' and all courses that are newly created will be updated with your template course. BAM!

The logic of the tool is essentially this:

  1. Configure your domain and token.
  2. Tell the script the canvas course ID of the most recently created course. Any courses that are created after this one will have the template applied to it, with one exception.
    1.  Exception: The script will check each course to look for existing content.  If content exists in the course, the template will not be applied. There were a couple of requests for this feature. If you prefer not to use it, you can remove the
      if (getCourseChanges(check_course_id) == 0)
      from within the processCSV function.
  3. Tell the script what is the course that you want to use as a template
  4. The script then creates and downloads a courses.csv provisioning report and compares each course to see if it is newer than the  course mentioned in step 2. If a course is newer, then apply the template course using a content_migration API endpoint.


For a better user experience, the script then gets the status of the migration and updates a cell when the migration is complete. I also made the name of each course a link to the course to make it easy to verify content.  


How to Use the Tool:

These instructions are in the 'Instructions' tab in the spreadsheet.

Configuration Instructions - This only needs to be done once

  1. In the 'Canvas Menu' select 'Configure API Settings'
  2. When prompted, Authorize the script by clicking on 'Authorize.'
  3. Select an email address to run the script.
  4. Select Allow
  5. In the 'Canvas Hostname' box, enter the URL of your Canvas instance. For example
  6. In the 'Access Token' box, enter your token. (For help creating the token, click on the ' How do I obtain an API access token for an account?' link right below the box.)
  7. Click 'Submit'
  8. If the Notice box says 'Using <> for your Canvas Hostname.' then click OK. Otherwise click 'Cancel' and repeat steps 5-7.
  9. In the 'Canvas' Menu select 'Don't Apply Template to Courses Created Before This Course ID'. Enter the Canvas course ID of the most recently created course in your instance and click OK. If you want to look at a list of all your courses, select 'Show All My Courses' from the 'Canvas' menu and wait a few minutes for the courses.csv report to create & populate the 'CurrentCourses' tab.
  10. In the 'Canvas' Menu select 'Set Template Course' and enter the Canvas course ID of your template course and click OK. 


Applying the Template Course

  1. In the Canvas menu, select 'Apply Template to Unchanged & New Courses'
    1. The Google sheet will now get a Courses Provisioning report and work it's magic. In a few minutes, you will see list of your courses in the 'Current Courses' tab.
    2. After the courses display on the CurrentCourses Tab, the new courses will appear on the NewCourses tab and automatically apply the template to the new courses.
    3. After another minute or so, the 'Status' and date/time' columns will update when the template course is applied
    4. There are links on the courses for your convenience
    5. Note: Google Scripts have a time limit. If you have a larger institution with hundreds of thousands of courses, this script may time-out. If it does, you can re-start the 'status update' by selecting 'Update Status of Template Copying' from the Canvas menu.
  2. If you wish to automate this and run it on a daily timer, select Tools > Script Editor > Edit > Current project's triggers. Then create a trigger to run updateNewCourses'.



As mentioned above Google App Script have limitations. Depending on the size of your institution, the script may time out. If that happens you're either a HUGE institution or making a LOT of changes. You may want to remove the 'if (getCourseChanges(check_course_id) == 0)' as mentioned above.

Just as a point of reference, I have worked with one institution that has almost 600K courses. That report takes about 12 minutes to create, so I estimate around 50K courses per minute to create the users.csv file. Your milage may vary.

The time required to apply the template course will also vary based on the quantity of material in the template.


What's Next:

  • Frankly, I'm not thrilled with the getMigrationStatus() function. If you feel the desire to help, please see the comments in the code.
  • I know my code isn't always optimized as good as it could be. If/when you find ways to improve it, please let me know. I love to learn and appreciate any help.
  • If you add more feature & functionality to this, please share back to the community. 



James Jones - The Configure API Settings and Forget API Settings come straight from his super work. If you haven't seen his Canvancements, prepare to be amazed!

Jeremy Perkins - Thanks for showing me how to pull reports and put them into sheets! 


Link to Template

I almost forgot... Here is a link to the template

You'll need to make a copy of it in your own drive first.


Video Demo


Sep 19, 2018 > Sep 21, 2018 12:28 PM

Jun 6, 2018

May 31, 2018



If you're a system administrator of a Canvas LMS instance with a deep organization of sub accounts you have inevitably found yourself in one of Dante's 9 Circles of Hell, repetitively clicking Sub Accounts at each and every level as you drill down to where you need to go. Here at CCSD we have over 8,000 sub accounts, and yet this only affects 5 people. So we will share this to help anyone else who is trapped.


The JavaScript and CSS files here add a directory style recursive HTML menu to the Canvas global navigation admin tray...


In Pictures

Admin Tray CollapsedAdmin Tray ExpandedAdmin Tray Search

Configuration & Setup

Zero to little configuration is needed for admintray-subaccmenu.js, so I won't even bother explaining subacctray.cfg


Option 1

  1. Host the file admintray-subaccmenu.js on a secure server (https) or somewhere like Amazon S3
  2. Copy/append the contents of to your Canvas Theme JavaScript file, point the URL to the hosted file.

Option 2 (Quick Start)

  1. Just copy the example snippet below that uses this repo's version and RawGit   to your Canvas Theme JavaScript file. However, please note that the RawGit URL points to the repo source and any changes to it may affect your usage later. I recommend hosting your own for stability, but this can get you started.


Once loaded the script will initialize an API call (to /api/v1/accounts/self/sub_accounts) and loop through x/100, collecting every sub account in your instance, compile a recursive HTML unordered list and store it your browser's localStorage.

Depending on the number of your sub accounts and internet speed, this will take a moment, be patient for the first load, open the tray and wait for it to show up. This takes us about 45-60 seconds on production. You will see a loading indicator in the Admin Tray while it compiles.


Features & Use


Instance Independent

There are some users (like Instructure Canvas Remote Admins) who may login to multiple Canvas Instances/institutions, so each menu will be stored in localStorage based on the uniqueness of, including,, and

For most users and institutions this will go mostly unnoticed unless you have different sub accounts between your Production, Test and Beta environments. I made this update to help those users it will affect. I also personally hate copying, pasting or replicating files just to change 1 line. This update allows 1 file to be hosted on a CDN like Amazon S3 and simply change the var show_results_parent value in or leave it blank.

Therefore an already minified file has been provided in the repo.


Alphabetical Sorting

Yup! As far as I know, the Canvas API does not allow sorting API calls alphabetically during pagination. The entire stack of sub accounts is sorted prior to building the menu.

Localized Search

Using JavaScript/jQuery to search within the stored HTML, preventing further API calls. You can search the entire sub account menu by name.

Search Result - Prefix Parent Account (Skip-to-Depth Display)

I don't know what else to call it, so here is an explanation.

Suppose your directory structure looks something like the following, where (#) is the depth of the account.

  • High Schools (1)
    • George Washington HS (2)
      • Course Shells (3)
      • SIS Courses (3)
        • English (4)
        • Math (4)
        • Science (4)
  • Middle Schools (1)
    • Betsy Ross MS (2)
      • Course Shells (3)
      • SIS Courses (3)
        • English (4)
        • Math (4)
        • Science (4)


When we search for Science and get multiple sub accounts of 'Science', we can't identify which one we want to choose.

  1. Science
  2. Science

So if we map the results depth of 4 to it's parent depth at 2 (instead of 3, SIS Courses) we can get a result like:

  1. George Washington HS > Science
  2. Betsy Ross MS > Science


And both are links to their respective account.



// one skip
show_results_parent = { 4:2 }
// expected result:
// George Washington HS > Science

// or multiple skips, must be unique
show_results_parent = { 4:2, 3:2 }
// expected results:
// (4:2) George Washington HS > Science
// (3:2) George Washington HS > SIS Courses

Note: If you don't define the skip, it will not display a parent


The ↻ button at the bottom right of the menu will clear the menu from localStorage and recompile it for the current Canvas instance. Use this when you or other admins have added or removed sub accounts.


User Impact

As mentioned above, CCSD has 5 system admins, with 40,000 Employees and over 300,000 Students. Be kind to your users, use the snippet below to reduce the impact of your admin-only tools. This is included in the repo as

if (ccsd.util.hasAnyRole('admin','root_admin')) {
// used for search results, result:parent, see documentation for more details
var show_results_parent = {}
// async load the sub account menu script
url: '',
dataType: 'script',
cache: true,
data: {skipd: JSON.stringify(show_results_parent)}


User Script

At the suggestion and some coaching by James Jones, I have created a User Script version. This is useful for those admins that can't or don't want to install this script in their Canvas Theme/Global JavaScript. This script is identical to the global JavaScript file, except that the CSS will be added to the DOM by the script and has the various userscript requirements at the top for Tampermonkey.

  1. You will need to install and enable the Tampermonkey browser extension
  2. Install the UserScript version of admintray-subaccmenu.user.js


Known Issues

If you are not a root admin of your Canvas Instance, you will need to set (1) sub account in the root setting. At this time you cannot add multiple sub accounts. I am planning to fix this.


Code repo here...

ccsd-canvas/admintray-subaccmenu at master · robert-carroll/ccsd-canvas · GitHub



Credits for Blog Post Banner Image

Public domain

Chart of Hell
File:Sandro Botticelli - La Carte de l'Enfer.jpg - Wikimedia Commons

Botticelli : de Laurent le Magnifique à Savonarole : catalogue de l'exposition à Paris, Musée du Luxembourg, du 1er octobre 2003 au 22 février 2004 et à Florence, Palazzo Strozzi, du 10 mars au 11 juillet 2004. Milan : Skira editore, Paris : Musée du Luxembourg, 2003. ISBN 9788884915641


This media file is in the public domain in the United States. This applies to U.S. works where the copyright has expired, often because its first publication occurred prior to January 1, 1923. See this page for further explanation.