Converting script from Rhino to V8

23 views
Skip to first unread message

CSL Marketing

unread,
7:20 AM (16 hours ago) 7:20 AM
to Google Apps Script Community
We have online training that is built using Articulate Storyline and we then package and send to our website host to publish.  This was built like 10 years ago and the build is no longer supported. The Apps script that sends the results to a Google sheet is no longer working due to the change to V8.

I have only just got access to the script and have no idea what needs changing to convert it from Rhino to V8 compatibility. 

Emerson Maia

unread,
7:49 AM (15 hours ago) 7:49 AM
to google-apps-sc...@googlegroups.com
First thing to check: have you already switched this Apps Script project to the V8 runtime in the editor (Project Settings → Runtime → V8)? If not, please enable V8 first and let us know if the issue persists. If that doesn’t fix it, we’ll probably need to update parts of the code, because some Rhino-only syntax isn’t compatible with the V8 runtime.



configurarv8.png


Expert  Docs

Emerson Maia

Goiânia Go

Brazil




On Tue, Jun 23, 2026 at 8:20 AM CSL Marketing <kemsol...@gmail.com> wrote:
We have online training that is built using Articulate Storyline and we then package and send to our website host to publish.  This was built like 10 years ago and the build is no longer supported. The Apps script that sends the results to a Google sheet is no longer working due to the change to V8.

I have only just got access to the script and have no idea what needs changing to convert it from Rhino to V8 compatibility. 

--
You received this message because you are subscribed to the Google Groups "Google Apps Script Community" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-apps-script-c...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/google-apps-script-community/c8b9a9bd-8473-4d92-afd9-2f6ae19f79aen%40googlegroups.com.

Alan Wells

unread,
7:49 AM (15 hours ago) 7:49 AM
to Google Apps Script Community
The documentation is at:

Step 1: Enable the V8 Runtime

Toggle the runtime directly in the Apps Script editor:

  1. Open your Apps Script project.

  2. Click on Project Settings (the gear icon on the left sidebar).

  3. Check the box that says Enable Chrome V8 runtime

Step 2: Rewrite Code if necessary

There are a few changes that might cause your script to throw errors

1. Extraneous Comma in Object Literals

Rhino ignored trailing commas in object definitions; V8 will throw a syntax error.

  • 🛑 Rhino (Broken in V8): var obj = { a: 1, b: 2, };

  • V8 (Fixed): const obj = { a: 1, b: 2 };

2. Modern Variable Scoping (var vs let/const)

In Rhino, var had function-level scope. V8 introduces block-scoping. If you start swapping var for let or const, make sure you aren't trying to call a variable outside of the {} block it was defined in.

3. Logger.log() Formatting

In Rhino, Logger.log() allowed SQL-style formatting string inputs (like %s). V8 prefers standard string concatenation or, better yet, modern template literals.

  • 🛑 Rhino: Logger.log("User %s logged in", username);

  • V8: Logger.log(\User ${username} logged in`);`

4. Direct Object/Array Modifications

V8 is much stricter about modifying built-in prototypes. If your script alters standard objects (like adding custom methods directly to Array.prototype), it might behave unexpectedly or throw errors.

Feature
Old Rhino Way
New V8 Way
Arrow Functions
function(x) { return x * 2; }
x => x * 2
Template Literals
"Hello " + name + "!"
`Hello ${name}!`
Destructuring
var first = array[0]; var second = array[1];
const [first, second] = array;
Classes
Prototypes and closures
Standard class MyClass { ... } syntax

Are you encountering a specific error message after turning on V8, or would you like me to review a specific piece of your script for compatibility?

CSL Marketing

unread,
10:03 PM (1 hour ago) 10:03 PM
to Google Apps Script Community
This is the script, it was written back in 2017 and last modified in 2020.  I do have V8 enabled but it is just not writing data to the Sheet. The error is just showing  "Execution failed. The Rhino runtime is deprecated and no longer supported."

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

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

// 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
 // 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());
}


SMAARTE Group

unread,
10:11 PM (1 hour ago) 10:11 PM
to google-apps-sc...@googlegroups.com
I implore everyone to use AI.  AI might not solve everything in one shot, but for relatively simple items it works like a charm.  Haven't tested this, but it has to have moved the ball forward.  Oh and get those form IDs into ScriptProperties.

I can certainly help you update this script!

The main reason your script is failing in the V8 runtime isn't actually V8 itself, but rather a few deprecated Google Apps Script methods and older JavaScript habits that the old Rhino runtime ignored but V8 enforces.

Here are the main fixes made in the updated code below:

  1. LockService.getPublicLock() is deprecated: Google replaced this with getScriptLock(). This is almost certainly what is causing your execution error.

  2. Variable Shadowing: Your main function is handleResponse(e) but your error catcher is catch(e). Using the same variable name e for both causes conflicts in modern JavaScript. I changed the error variable to err.

  3. Array Iteration: Using for (i in headers) is discouraged for arrays in modern JavaScript (ES6/V8) and can cause unexpected bugs. I updated this to a standard for loop.

  4. Modern Syntax: Updated var to const and let for better memory management and strictness in V8.

Important Final Step:

Because this acts as a Web App, simply saving the script will not apply your changes to the live URL. You must re-publish it:

  1. In the Apps Script editor, click Deploy > New deployment (or "Manage deployments" -> Edit -> New Version).

  2. Ensure it is set to Execute as: Me and Who has access: Anyone.

  3. Click Deploy. (Your Web App URL should remain the same if you edit an existing deployment, but ensure you test with the new version).



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

// 2. Enter the KEY of your form
const KEY = "1GRmZeZBXZ6327b_zCXIc9iCDav8yxCJJFpQCijHK6OU";

// 3. Run > setup

// 4. Publish > Deploy as web app (In new editor: Deploy > New Deployment)
// - enter Project Version name and click 'Deploy'
// - set security level and enable service (Execute as 'Me', Access 'Anyone')

// 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)

const SCRIPT_PROP = PropertiesService.getScriptProperties();

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

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

function handleResponse(e) {
  // getPublicLock() was deprecated. We must use getScriptLock() in V8.
  const lock = LockService.getScriptLock();
  lock.waitLock(30000); // wait 30 seconds before conceding defeat.

  try {
    // next set where we write the data
    const doc = SpreadsheetApp.openById(SCRIPT_PROP.getProperty(KEY));
    const sheet = doc.getSheetByName(SHEET_NAME);

    // we'll assume header is in row 1 but you can override with header_row in GET/POST data
    const headRow = (e && e.parameter && e.parameter.header_row) ? e.parameter.header_row : 1;
    const headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0];
    const nextRow = sheet.getLastRow() + 1; // get next row
    const row = [];
   
    // Modern standard loop instead of 'for...in'
    for (let i = 0; i < headers.length; i++) {
      if (headers[i] === "Timestamp") { // special case if you include a 'Timestamp' column
        row.push(new Date());
      } else { // else use header name to get data
        // Check if parameter exists to avoid undefined errors
        const value = (e && e.parameter) ? e.parameter[headers[i]] : "";
        row.push(value === undefined ? "" : value);
      }
    }
   
    // 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(err) {
    // Changed catch(e) to catch(err) to prevent shadowing the 'e' from handleResponse(e)
    return ContentService
      .createTextOutput(JSON.stringify({"result": "error", "error": err.message || err.toString()}))
      .setMimeType(ContentService.MimeType.JSON);
  } finally {
    //release lock
    lock.releaseLock();
  }
}

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


Regards,
Steve Horvath



--
You received this message because you are subscribed to the Google Groups "Google Apps Script Community" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-apps-script-c...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages