- ⚠️ Custom functions in Google Apps Script cannot change what's in a sheet. This is due to security rules that limit what they can do.
- 🧠 Functions called from cell formulas only read data. They just give back values.
- 🔒 You must give scripts special permission (OAuth scopes) to write data or use other online services.
- 🛠️ Using installable triggers or custom menus lets scripts read and write everything.
- 🧪 To fix problems with custom functions, test parts of the code in the Apps Script editor.
Why Your Google Apps Script Cannot Write to a Sheet Cell
Many developers get frustrated when they try to write to a Google Sheet cell with a custom function, and nothing happens. The script runs, but no output shows up. There is no error, and no crash, just silence. This explains what is happening and how to make scripts that work as you want them to.
What Custom Functions Are in Google Apps Script
Google Apps Script lets you make custom functions. They work much like the formulas already in spreadsheets. People often use these to change input values and then put the changing output right into a cell.
Here is a simple example of how a custom function looks:
function doubleValue(input) {
return input * 2;
}
After you set it up, you can call it from a sheet like this:
=doubleValue(A1)
These functions are very helpful for special calculations and changing how things work. But, they have very few ways to interact with the spreadsheet. Custom functions run in a safe, read-only space. This means they cannot do things like write to other cells, change selections, send emails, or use services that need special permission.
What Custom Functions Cannot Do
Google puts strict limits on what custom functions can do when you run them from a cell. This is on purpose. These limits keep Google Sheets secure, fast, and predictable. The official documents say:
“Custom functions cannot perform actions that cause side effects.”
Google Developers
Side effects are any actions that do more than just give back a value. These include writing to a sheet cell, changing how it looks, or talking to another online service.
Why are there such strict limits?
There are three main reasons:
- ✅ Security: This stops bad functions from running scripts they should not.
- ✅ Stability: This prevents issues like endless loops or changes to sheets from a formula.
- ✅ Performance: This makes sure spreadsheet calculations stay quick and dependable.
So, even if you try to write something using sheet.getRange().setValue() inside a custom function, you will not get an error. The script just will not run that part.
How Google Apps Scripts Get Permissions
Knowing how scripts start in Google Sheets helps you pick the right way to do your work.
1. Custom Functions
You call these functions right from inside a Google Sheet cell.
- Starts with: A formula in a cell (for example,
=myFunction(A1)) - ✅ Can read data from the spreadsheet
- ❌ Cannot write to cells or change the spreadsheet
- ❌ Cannot use services that need permission
- ✅ Run on their own, without needing any permission
Custom functions take in values, work with them, and then put results back into the same cell.
2. Installable Triggers (for example, onEdit, onOpen)
Triggers are functions that run on their own when something happens, like editing a cell.
- Starts with: An event, such as editing, opening a sheet, or sending forms
- ✅ Can read and write data
- ✅ Can use services like Gmail, Calendar, and Drive
- ✅ Can get cell formats, names for ranges, and more
- 📌 Need you to give permission first
These triggers help run tasks on their own after you set them up.
3. Scripts You Run Yourself
These are scripts a user starts from a menu or in the Apps Script editor.
- Starts with: A menu button, the script editor "Run" button, or another assigned button
- ✅ Have full access to read and write
- ✅ Can use protected services and APIs
- 📌 Need you to give permission one time
Manual scripts give you the most freedom for scripting. They work best for tools you click once or for tasks that run on many items.
An Example: Why Your Custom Function Does Not Write
Let's look at a common mistake:
function writeData() {
SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName("Sheet1")
.getRange("B1")
.setValue("Hello World");
}
You use it like this:
=writeData()
At first, this code looks correct. But it will not write anything to cell B1 when you try it in a spreadsheet cell. Why?
The Problem:
When writeData() starts from a spreadsheet cell:
getActiveSpreadsheet()gives back an object that is in a safe, limited area.setValue()tries to write, but this breaks the "no side effects" rule.- Google Sheets stops this action without telling you.
- You will not see any warning, error, or result.
The action to write to a Google Sheet cell gets blocked without any notice. This happens because of security and speed limits.
Why Custom Function Errors Do Not Show Warnings
It can be very frustrating that bad actions in custom functions—like writing to a cell—do not cause normal error messages.
Instead:
- The function just gives back
undefined. - The cell with the formula stays empty or shows
#ERROR!without explaining why. - You cannot easily see logs unless you run the function yourself.
This unclear feedback can make fixing code confusing for hours. Because of this, it is very important to write code in small, separate pieces. And then test the writing parts in a different script, not inside custom functions.
Ways to Write to Cells When Custom Functions Cannot
Custom functions cannot write to cells. But you can still do the same job in other ways using Apps Script.
1. Use a Function Started by a Button
Here is a script that starts when you click a button:
function writeToCell() {
var sheet = SpreadsheetApp.getActive().getSheetByName("Sheet1");
sheet.getRange("B1").setValue("Triggered by button");
}
You can link this writeToCell() function to a drawing or picture in your sheet. Use the Assign Script menu. This lets you:
- Control when the function runs.
- Give it full permission to write (after you approve it once).
- Get results that always act the same way.
2. Use Menu Options
You can add a custom menu that shows up when you open the spreadsheet:
function onOpen() {
SpreadsheetApp.getUi()
.createMenu("My Tools")
.addItem("Write Hello to B1", "writeToCell")
.addToUi();
}
This makes a menu where people can choose when to run the writing code.
Using Triggers That Respond to Events
Event triggers are another way to run code that writes data. They do not have the limits of custom functions.
Simple onEdit Trigger:
function onEdit(e) {
var sheet = e.source.getActiveSheet();
if (sheet.getName() === "Sheet1" && e.range.getA1Notation() === 'A1') {
sheet.getRange("B1").setValue("Edited A1");
}
}
This code runs on its own when someone edits cell A1. Unlike custom functions, onEdit() can change cell values. (It still has some limits).
Installable Triggers
Installable triggers (which you set from code or by hand in the system) let you do stronger things. For example:
- Sending emails
- Making web requests
- Writing to many areas at once
You can set installable triggers like this:
function createTrigger() {
ScriptApp.newTrigger("myFunctionToRun")
.forSpreadsheet(SpreadsheetApp.getActive())
.onEdit()
.create();
}
You can learn more about triggers in Google’s documentation.
What OAuth Scopes Are and Why They Are Important
For your script to write to cells, get to Drive, or use Gmail, it needs permission through something called OAuth scopes.
Here is a common scope:
https://www.googleapis.com/auth/spreadsheets
Apps Script will ask for these permissions on its own when your script:
- Writes data to the sheet
- Sends email
- Uses other online services
But when you use custom functions, the system will not ask for these permissions. This is because read-only mode does not need them.
You can check and control these scopes using:
- Appsscript.json
- Permission review screens
- Advanced settings in Apps Script
Learn more about scopes on Google’s OAuth2 documentation page.
Why Google Limits Custom Functions to Only Return Values
This is about the idea of pure functions in programming. A pure function:
- Always gives the same answer for the same input.
- Has no side effects (it does not change anything outside itself).
This makes calculations easy to repeat, safe to store, and quicker. These are important for a spreadsheet system like Google Sheets that can handle many users and large files.
If custom functions could write data:
- They might cause endless write loops.
- They could change user data without warning.
- They could run bad code in shared Sheets.
That is why you will never be able to write to a Google Sheet cell from inside a custom function.
How to Fix Custom Function Errors in Google Apps Script
Here are some good ways to find and fix errors:
1. Use Logger.log (You can only see this if you do not run it from a sheet)
function testLogging() {
Logger.log("Testing logs!");
}
After you run it in the Script Editor, go to View > Logs.
2. Use try...catch Blocks
function safeReturn(x) {
try {
return x * x;
} catch (err) {
return "Error: " + err.message;
}
}
3. Execution History
Open the Executions panel. This shows how functions run, if there are permission problems, and any hidden errors.
Good Ways to Write Data in Google Sheets Scripts
To keep your scripts working well, steady, and safe:
- ✅ Keep code separate. Make some functions for reading only and others for writing.
- ✅ Do not let custom functions have side effects. This makes fixing problems easier.
- ✅ Test writing code that is tricky in the Apps Script editor before you use it widely.
- ✅ Use buttons or custom menus to control when writing happens.
- ✅ Deal with odd situations, empty values, and errors in a good way.
- ✅ Write lots of comments. You will be glad you did later.
An Example: Checking Input in a Sheet
Job: When someone types data in column A, we want to write "Valid" or "Invalid" in column B.
How to do it:
function validateInput() {
var sheet = SpreadsheetApp.getActive().getSheetByName("Sheet1");
var data = sheet.getRange("A2:A").getValues();
for (var i = 0; i < data.length; i++) {
if (!data[i][0]) break;
var result = typeof data[i][0] === 'number' ? "Valid" : "Invalid";
sheet.getRange(i + 2, 2).setValue(result);
}
}
Add this to a custom menu:
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu("Data Tools")
.addItem("Run Validation", "validateInput")
.addToUi();
}
This way of working is safer and more reliable. It also keeps you from getting stuck by the custom function error. Check data only when the user chooses to do so, with full writing permissions.
Summary: What Google Apps Script Functions Can and Cannot Do
Here is a quick look at everything:
| Action | Custom Function | Script You Run | Trigger |
|---|---|---|---|
| Read Cell Values | ✅ Yes | ✅ Yes | ✅ Yes |
| Write to Cells | ❌ No | ✅ Yes | ✅ Yes |
| Use APIs (like Gmail) | ❌ No | ✅ Yes | ✅ Yes |
| Needs Permission | ❌ No | ✅ Yes | ✅ Yes |
| Good for Calculations | ✅ Yes | ✅ Yes | ✅ Yes |
Main points to remember:
✔ Use custom functions to give back values.
❌ Do not try to write inside function formulas.
✅ Use installable triggers or menus to let users interact.
🔐 Understand what permissions scripts need.
By using these good ways of working and knowing how Google Apps Script is built, you will avoid common problems, such as the well-known custom function error. And you will use the great power of Sheets to do tasks on their own.
Get Better at Scripting with Devsolus
At Devsolus, we focus on helping developers fix script problems in the real world clearly and with confidence. If you have ever run into strange limits in Google Apps Script, know that there are better tools and smarter ways to work. Keep trying things, build your code well, and ask the community for help when you need it.
Citations
Google Developers. (n.d.). Custom Functions in Google Sheets
Google Developers. (n.d.). Triggers — Google Apps Script
Google Developers. (n.d.). Authorizing requests with OAuth 2.0