Scriptdrill

Reading and writing sheets Updated November 2026

Protect ranges and sheets

range.protect() creates a protection on that range (sheet.protect() for a whole tab); by default everyone keeps edit rights, so call protection.removeEditors(protection.getEditors()) and then addEditor for the people allowed. setWarningOnly(true) shows a warning instead of blocking. Only owners and editors with permission can protect.

Syntax

const p = range.protect().setDescription(text); p.removeEditors(p.getEditors()); p.addEditor(email)
PartWhat it is
setDescription(text)Label shown in the Protected sheets and ranges panel
removeEditors(emails)Removes edit permission for the listed users; the owner always keeps it
addEditor(email) / addEditors(emails)Users who may edit the protected cells
setWarningOnly(true)Warn before editing instead of blocking
setUnprotectedRanges(ranges)On a sheet protection, leave some ranges editable

Examples

const sheet = SpreadsheetApp.getActiveSheet();
const p = sheet.getRange("A1:C1").protect().setDescription("Headers");
p.removeEditors(p.getEditors());
if (p.canDomainEdit()) p.setDomainEdit(false);

Result: Only the owner (and the script runner) can edit A1:C1

const p = sheet.getRange("E2:E100").protect().setDescription("Approvals");
p.removeEditors(p.getEditors());
p.addEditor("manager@example.com");

Result: The manager and the owner can edit the approval column; others are blocked

const p = sheet.protect().setDescription("Locked report");
p.setUnprotectedRanges([sheet.getRange("B2:B10")]);

Result: Whole tab locked except the input cells B2:B10

sheet.getProtections(SpreadsheetApp.ProtectionType.RANGE).forEach(p => {
  if (p.getDescription() === "Approvals") p.remove();
});

Result: Removes the Approvals protection

Common mistakes

  • The protection exists but everyone can still edit: you forgot removeEditors(getEditors()); a fresh protection keeps all current editors.
  • You do not have permission to protect: only the spreadsheet owner or editors who were not restricted can create protections; the script runs as the current user.
  • Running the script twice stacks duplicate protections: check getProtections first and reuse or remove the old one by description.
  • Editors from your Workspace domain still edit: domain-wide edit access is separate; call setDomainEdit(false) when canDomainEdit() is true.

Practice Protect ranges and sheets

These drills check your answer on live data, free, no account needed.

  • Pick some keysReturn a new object with only the listed `keys` of `obj`. Skip keys that `obj` does not have, but keep keys it has even when the value is `0`, `false`, `null`, `""` or `undefined`. Do not change `obj`.

Questions

Can a protected range stop the script itself from writing?

No. Scripts run with the permissions of the user who runs them (or the trigger owner), so a protection does not block a script run by the owner.

How do I protect every sheet in the file?

Loop ss.getSheets() and call sheet.protect() on each, removing editors the same way. Keep one unprotected input tab if people need to enter data.

Related

  • Clear and format cellsClear and format Google Sheets cells with Apps Script: clear content or formats, set background and font color, bold, number and date formats, borders.
  • onEdit triggerUse the onEdit trigger in Google Apps Script: the event object with range, value and oldValue, limiting it to one sheet or column, timestamps, installable.
  • getActiveSheet vs getSheetByNameChoose between getActiveSheet and getSheetByName in Google Apps Script: when the active sheet is unreliable, targeting a tab by name, and missing sheets.
  • Installable triggersInstallable triggers in Google Apps Script: how they differ from simple triggers, creating them from the UI or ScriptApp.newTrigger, onChange, onFormSubmit.

Previous: getActiveSheet vs getSheetByNameNext: Clear and format cells