Articulate Storyline: Export to Google Drive

Nov 18, 2015

PREVIEW  |  SOURCE

On the Articulate user days in Utrecht (2015), we held a session about exporting Articulate Storyline variables to Google Drive (Spreadsheet). This export is achieved via JavaScript (jQuery).

Use the button Source to download the Storyline project. If you want the same lay-out as the example above, please install the following fonts (see source file):

  • flaticons-stroke.ttf
  • fontawesome-webfont.ttf

Why do you want to make an export to Google Drive?

  • No LMS (or database) available;
  • Store more information than just the test results. You can export all Storyline variables to Google Drive.

Why using Javascript?

Besides using Javascript it's also possible to embed a Google form as WEB object. This is a lot easier than using Javascript.

We have chosen for Javascript because we would like the ability to change the appearance of the form. In addition, we want to collect data across multiple slides and then store them in Google Drive.

UPDATE 2017-06-06:

There is also an article available for importing records of a Google Spreadsheet into Storyline:

Articulate Storyline: Import from Google Drive

UPDATE 18-10-2018: PROBLEMS WITH NEW SPREADSHEET, TRY TO USE A TEMPLATE

Google changed somthing within the mechanism of storing variables into a Google Spreadsheet. Creating a new spreadsheet can give you problems for storing variables. Before you try the steps below, please use a template:

Go to the page below and use the button Use this template:
https://drive.google.com/previewtemplate?id=1vrqb9ykwCSxzjcBIpYO7P9AXPyh37J3HviSwhZvYc_U&mode=public

And go further with step 4 below!

Export to Google Drive

The export consists of several steps. Some steps take place on the side of Google. For these steps you will need a Google account. The remaining steps take place in Articulate Storyline.

Below you'll find the steps to create the export to Google Drive: 

1. Login with your Google account

Go to the page below and login with your credentials:
https://docs.google.com/spreadsheets/

2. Create a new spreadsheet

Click on the Plus-sign (+) to create a new spreadsheet.

3. Rename the sheet to DATA

Give the spreadsheet a title and change the name of the sheet to DATA.

4. Add extra columns

Add extra columns you would like to use. Probably these columns will have the same name as the variables in Articulate Storyline. As example: the column names name, email and message like in the source project.

You can add the column date in the spreadsheet, if you would like to save the date when the form is sent to Google.

The column names needs to be identical to the variable names in Articulate Storyline. The column names are case sensitive.

 5. Copy the ID of your form

Find out your spreadsheet ‘key’ by looking in the address bar, the key is the long series of letters and numbers after /d/ and before /edit: Like:

https://docs.google.com/spreadsheets/d/1AzBuim89ma_ght1-O14cksVzXrQL5Vh4XnRqY9OM_gc/edit#gid=0

The KEY will be = 1AzBuim89ma_ght1-O14cksVzXrQL5Vh4XnRqY9OM_gc

Save this KEY in a Notepad file to keep safe, or other application, you will need this ID in step 8.

6. Open the Script Editor

Open the script editor Tools, Script Editor.

7. Paste custom script

If you are using the template, then you can skip this step. The code is already in the template available. If not, paste the script below, which is needed for importing the Storyline variables into this spreadsheet:

// 1. Enter sheet name where data is to be written below
var SHEET_NAME = "DATA";

// 2. Enter the KEY of your form
var KEY = "KEY"

// 3. Run > setup

// 4. Publish > Deploy as web app
// - enter Project Version name and click 'Save New Version'
// - set security level and enable service (most likely execute as 'me' and access 'anyone, even anonymously)

// 5. Copy the 'Current web app URL' and post this in your form/script action

// 6. Insert column names on your destination sheet matching the parameter names of the data you are passing in (exactly matching case)

var SCRIPT_PROP = PropertiesService.getScriptProperties(); // new property service

// If you don't want to expose either GET or POST methods you can comment out the appropriate function

function doGet(e){
return handleResponse(e);
}
function doPost(e){
return handleResponse(e);
}

function handleResponse(e) {
// shortly after my original solution Google announced the LockService[1]
// this prevents concurrent access overwritting data
// [1] http://googleappsdeveloper.blogspot.co.uk/2011/10/concurrency-and-google-apps-script.html
// we want a public lock, one that locks for all invocations
var lock = LockService.getPublicLock();
lock.waitLock(30000); // wait 30 seconds before conceding defeat.

try {
// next set where we write the data - you could write to multiple/alternate destinations
var doc = SpreadsheetApp.openById(SCRIPT_PROP.getProperty(KEY));
var sheet = doc.getSheetByName(SHEET_NAME);

// we'll assume header is in row 1 but you can override with header_row in GET/POST data
var headRow = e.parameter.header_row || 1;
var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0];
var nextRow = sheet.getLastRow()+1; // get next row
var row = [];
// loop through the header columns
for (i in headers){
if (headers[i] == "Timestamp"){ // special case if you include a 'Timestamp' column
row.push(new Date());
} else { // else use header name to get data
row.push(e.parameter[headers[i]]);
}
}
// more efficient to set values as [][] array than individually
sheet.getRange(nextRow, 1, 1, row.length).setValues([row]);
// return json success results
return ContentService
.createTextOutput(JSON.stringify({"result":"success", "row": nextRow}))
.setMimeType(ContentService.MimeType.JSON);
} catch(e){
// if error return this
return ContentService
.createTextOutput(JSON.stringify({"result":"error", "error": e})) .setMimeType(ContentService.MimeType.JSON);
} finally { //release lock
lock.releaseLock();
}
}

function setup() {
var doc = SpreadsheetApp.getActiveSpreadsheet();
SCRIPT_PROP.setProperty(KEY, doc.getId());
}

8. Paste your key

There is one place in the script where it says var KEY = "KEY". Copy and paste your key between the "".

9. Run the script

Run the script via Run, Run function, setup. The first time you run the script it will ask for permission to run. You will need to grant it. If you run the script for a second time you won't get any popup. This is an indication it has run successfully.

10. Deploy a web app

Go to Publish, Deploy as web app. Enter a project name (optional) and set security level. Choose for Me and access Anyone, even anonymously. Click on the button Deploy to create the web app.

11. Copy the Current web app URL

Copy the 'Current web app URL' and paste it in a Notepad file to keep safe.

Example URL:

https://script.google.com/macros/s/AKfycbyoP8c3_wlons5PSHx1W8PWJx4pn7t3ch-_IxTz0dVIKFw1AGLN/exec

12. Add jQuery library

In Articulate, add a trigger to run javascript (Execute Javascript) and use the code below.

This code will add the jQuery library to this project, so you won't have to change the HTML files after publishing the project. The jQuery library is needed for exporting the information to Google Drive.

var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.src = '//code.jquery.com/jquery-1.11.0.min.js';
script.type = 'text/javascript';
head.appendChild(script)

13. Store information

Add another trigger to run Javascript (Execute Javascript). You can use the code below.

Replace the value Current web app URL for the webapp url you've saved in step 11

Below the webapp URL, you can place the column names of the spreadsheet and the Storyline variables. Please be aware of the comma if you add multiple variables.

var player = GetPlayer();

//PLACE YOUR WEB APP URL
WEB_APP_URL = "Current web app URL";

// STORE ARTICULATE STORYLINE VARIABLES
// "Columnname_Google_Spreadsheet" : player.GetVar("Name_Storyline_Variable")
// ATTENTION: Use a comma if you use multiple Storyline variables
storyline =
{
"date" : new Date().toJSON().slice(0,10), //STORE DATE
"name" : player.GetVar("name"),
"email" : player.GetVar("email"),
"message" : player.GetVar("message")
}

Don't delete the row below, if you would like to save the date when the form is sent:

"date" : new Date().toJSON().slice(0,10), //STORE DATE

14. Export code to Google Drive

Latest Javascript code. Add another trigger to run Javascript (Execute Javascript). You can use the code below. This trigger will send the information from step 13 to Google Drive.

//DELAY SO JQUERY LIBRARY IS LOADED
setTimeout(function (){

//Export to Google
$.ajax({
url: WEB_APP_URL,
type: "POST",
data : storyline,
success: function(data)
{
console.log(data);
},
error: function(err) {
console.log('Error:', err);
}
});
return false;
}, 1000);

15. Publish to SCORM or WEB format

Publish your articulate project to WEB or SCORM format. You need to host it on a WEB server or somewhere like SCORM cloud (or a LMS).

This export will work in Flash and HTML5 output. You can't use the Articulate Mobile Player, because it won't support Javascript code.

Thank You

Thanks Kate Robertson for making the blog post below:
Exporting Variables into a Google Spreadsheet

I started with your setup and then have tried to simplify the steps by changing the Javascript code and importing the JQuery Library.

 

277 Replies
Mark Bawden

Hi Alison,

 

I'm afraid my problem seemed to 'resolve itself', in that I created a new Google Sheet from scratch and followed the instructions above. When you run your eLearn and check your report, do you see the words "undefined" in any of your fields? Or does nothing appear at all?

One possible troubleshooting method you may try is the following:
In the Script Editor for your Google Sheet (where you've copied and pasted the code), click on Publish, then Deploy as Web App. You'll notice that the box at the top displays your current web app URL, but also has a button labelled "Test web app for your latest code". Give that a click, and see what happens. If the test returns successfully, you'll see the words "undefined" have appeared in your spreadsheet.

If this happens, that means the report itself is set up correctly, and the issue may lie in the Javascript within your Storyline project. If the test does not run successfully, it might be an issue with the sheet itself. 

Hope this makes sense! Feel free to let me know if you need more clarification. Good luck getting this issue fixed up.

Cheers,

MB

Bastiaan Timmer

Hi,

I think Google changed something on the background. If I ran the Web App it returnes an error. So there must be something wrong within the code.

I will have to get some time to investigate this problem.

@Mark: did you create a new spreadsheet lately? Maybe old generated files are working fine.

Best regards,

Bastiaan

Alison Gretchen Stander

Hi Mark

I will definitely give it a try. The issue is that nothing appears at all. I know about the "undefined" issue, I have  had that before and could resolve it. I did try creating a new sheet, a couple of times. I even used a previous sheet and copied that and just added the new variables, and still nothing.

I think it might be something in SL, I don't know, but I will look at everything again.

Thanks for the help.

Joanna Kurpiewska

Hi Bastiaan

thanks so much for this awesome post.
Do you know (or any other e-learning hero) if it would possible to send data from Storyline and save it on local drive?
We're going to run a quiz on a wide audience using an iPad/laptop (tbc) but without access to internet so we would like Storyline to save some data to the same file on device. The type of the file can be .doc or .xls or whatever allows us to open it an consolidate data from other offline laptops.
I'd appreciate any suggestion.

Joanna

Jack Waller

Hi Joanna, 

I've looked at this before when running a pilot with no access to WiFi. There is definitely a way to export variables to a PDF, from memory it works better on certain browsers and it has to be exported when the storyline export is running. I'll see if I can find the tutorial I used before, it was definitely on here. Is that what you would be trying to do?

Jack

Bastiaan Timmer
Joanna Kurpiewska

Thanks for your reply guys. 

I need to clarify how this should work: user #1 is taking the quiz, at the end his data is saved to local drive. User #2 is taking the quiz, at the end his data is saved to local drive to the same file as for user 1 so we have one file only with data from multiple users. All new information is appended to existing data. We wouldn't like to have separate files for every user.

Here's what we'd like to store: name/surname, email, final score etc.

Is this feasible with javascript/ jquery or any other magic? Have you seen something similar already done?

 

 

Bastiaan Timmer

Hi Rian,

Thanks for the update.

Google changed something in the mechanism to write variables to a spreadsheet, so it isn't working at the moment. I will need to find some time to figure out what's going wrong.

But if the template is working fine, I will mention the template in the article. This template had problems before, that's why I've changed the steps within this article.

Thanks for figuring out!

Ryan Thomson

Thanks so much for this,  Bastiaan. :) 

I have a question - If I wanted to run a function once the new line is added, where would I call it within your code? I assumed it was at the end of the handleResponse function, but I can't get it working.

I'm trying to have the results sent to the user via email and I have a working send mail function, but I can't figure out when to call it. (I had thought I could use the onChange trigger, but as I"ve learned this is only for user-populated changes)

Thanks for any pointers!!

Bastiaan Timmer

Hi Ryan,

The code below is sending the information to Google:

//Export to Google
$.ajax({
url: WEB_APP_URL,
type: "POST",
data : storyline,
success: function(data)
{
console.log(data);
},
error: function(err) {
console.log('Error:', err);
}
});
return false;
}, 1000);

If you write your code below de line console.log(data); then it should work. This line is exporting the data to the spreadsheet.

Note: All the date is placed in a javascript variable called "storyline". If you want to use the values as seperate values, then you can use the code below:

var date = new Date().toJSON().slice(0,10);  //STORE DATE
var name = player.GetVar("name");
var email = player.GetVar("email");
var message = player.GetVar("message");

You can use the values date, name, email and message in your mail script/function.

 

Aaron Kapala

Hi there,

I am having problems with recording my data even though I have followed these instructions a number of times, Is anyone able to assist or spot what I may have done wrong?

I am trying to pull the variables from storyline into my GoogleSheet, variables are set up, triggers are done and I have set up to pass the PassPoints to a number variable called score.

I am currently testing this on an Amazon Web Server and all files are attached.

Bastiaan Timmer

Hi Aaron,

Google changed somthing within the mechanism of storing variables into a Google Spreadsheet. Creating a new spreadsheet can give you problems for storing variables. Before you try the steps above, please use a template:

Go to the page below and use the button Use this template:
https://drive.google.com/previewtemplate?id=1vrqb9ykwCSxzjcBIpYO7P9AXPyh37J3HviSwhZvYc_U&mode=public

And go further with step 4 above!

Maybe this solves the problem.

Best regards,

Bastiaan

Aaron Kapala

Hi Steve,

I did find an article about using Google Forms but as I started following it the set up looked different, so maybe it's something I need to look at in case this over option doesn't work.

The main thing is being able to record the data somewhere so we can then use the information and get the score they got after answering the questions.

Aaron Kapala

Hi Roberto,

I am just having a quick look at your file now. The problem you have got here is that the JavaScript triggers are firing off when the timeline starts on the same screen as where your entering the data so it won't work properly.

I have just ran a test, could you check your GoogleSheet to see if has updated? If so I will attach the updated file across to you and explain what I done.

Aaron Kapala

Hi Roberto,

So attached the new version, I made a couple of changes which were:

  • Removed a few extra JavaScript triggers you has which were not needed.
  • Amended the JavaScript trigger with the variables in to remove the coma on the last variable added.
  • I inserted a submit button which then just triggers to a layer with the JavaScript triggers on or alternatively you can have those triggers on the button itself but just be aware of the issues with the TextEntry boxes not submitting the content when using mobile/tablet devices. Seems to be an issue at the moment.

Hope that helps.

Best wishes,

Aaron