How to Turn a Google Sheet Into an API (Free, With Apps Script)
Turn a Google Sheet into a JSON API for free with an Apps Script web app. Copy-paste code, deploy steps, quotas and paid alternatives, checked 13 Oct 2026.
Quick answer: Write a short Apps Script with a doGet function (to read rows) and a doPost function (to add rows), then deploy it as a web app. You get a URL that returns your sheet as JSON. Free? Yes. Time: about 10 minutes.
Google documents this pattern directly: a web app script must contain a doGet or doPost function and return a TextOutput or HtmlOutput object. The rest of this guide gives you the full code, the deploy steps, the limits, and the safer and paid alternatives.
What do you need before you start?
You need a Google account and a Google Sheet with a header row. Put column names in row 1 (for example name, email, plan). Each later row is one record.
You do not need a Google Cloud project, a credit card, or a server for Method 1. You do need to be comfortable pasting code. If you also want to send email or messages from the same sheet, see our guides on sending emails from Google Sheets and Google Sheets alerts on WhatsApp.
How do you turn a Google Sheet into an API? (Method 1: Apps Script, free)
Open the sheet, add a script bound to it, paste the code below, and deploy it as a web app. The script reads the header row, turns every other row into a JSON object, and returns the list.
- Open your Google Sheet. Rename the tab at the bottom to
Sheet1(or changeSHEET_NAMEin the code). - Click Extensions > Apps Script.
- Delete the sample code in the editor and paste the script below.
- Replace
CHANGE_ME_TO_A_LONG_RANDOM_STRINGwith your own long random text. This is your API key. - Click Save project.
const SHEET_NAME = 'Sheet1';
const API_KEY = 'CHANGE_ME_TO_A_LONG_RANDOM_STRING';
function json_(payload) {
return ContentService
.createTextOutput(JSON.stringify(payload))
.setMimeType(ContentService.MimeType.JSON);
}
function getSheet_() {
return SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SHEET_NAME);
}
// READ: GET <web app URL>?key=YOUR_KEY
function doGet(e) {
if (!e.parameter.key || e.parameter.key !== API_KEY) {
return json_({ error: 'unauthorized' });
}
const sheet = getSheet_();
if (!sheet) return json_({ error: 'sheet not found' });
const values = sheet.getDataRange().getValues();
const headers = values.shift();
const rows = values.map(function (row) {
const record = {};
headers.forEach(function (header, i) {
record[header] = row[i];
});
return record;
});
return json_({ count: rows.length, data: rows });
}
// WRITE: POST <web app URL> with body {"key":"YOUR_KEY","row":{"name":"Ada","email":"ada@example.com"}}
function doPost(e) {
let body;
try {
body = JSON.parse(e.postData.contents);
} catch (err) {
return json_({ error: 'body must be JSON' });
}
if (body.key !== API_KEY) return json_({ error: 'unauthorized' });
if (!body.row || typeof body.row !== 'object') {
return json_({ error: 'missing row object' });
}
const lock = LockService.getScriptLock();
lock.waitLock(10000);
try {
const sheet = getSheet_();
if (!sheet) return json_({ error: 'sheet not found' });
const headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0];
const newRow = headers.map(function (header) {
const value = body.row[header];
if (value === undefined || value === null) return '';
if (typeof value === 'string' && value.charAt(0) === '=') return '';
return value;
});
sheet.appendRow(newRow);
SpreadsheetApp.flush();
return json_({ ok: true });
} finally {
lock.releaseLock();
}
}
Now deploy it:
- At the top right of the Apps Script editor, click Deploy > New deployment.
- Next to "Select type," click the gear icon (Enable deployment types settings) and choose Web app.
- Under Deployment configuration, choose Execute the app as me. This means the script always runs as you, whoever calls it, as Google's web app guide describes.
- Set Who has access to the option that allows anyone, including people who are not signed in to Google. Verify this step: the dropdown label may differ. Google's manifest reference calls this level
ANYONE_ANONYMOUS. - Click Deploy. Approve the permission prompt when it asks. Verify this step: the screens may differ by account type.
- Copy the Web app URL. It ends in
/exec.
Test it by opening YOUR_WEB_APP_URL?key=YOUR_KEY in a browser, or run this in a terminal:
curl -L "YOUR_WEB_APP_URL?key=YOUR_KEY"
curl -L -X POST "YOUR_WEB_APP_URL" \
-H "Content-Type: application/json" \
-d '{"key":"YOUR_KEY","row":{"name":"Ada","email":"ada@example.com"}}'
The -L flag matters. A Digital Inspiration tutorial notes that Apps Script responses come through a redirect from script.googleusercontent.com, so tools such as curl and Postman must follow redirects. Google's TextOutput reference says browsers are redirected there too.
How do you update the API after you change the code?
Saving the script is not enough. Google's deployment docs say to create a new version and edit the deployment to use it. Click Deploy > Manage deployments, select the active deployment, click Edit, choose a new version, and click Deploy. The URL stays the same.
The Deploy > Test deployments link gives a /dev URL. Per Google, it always runs your latest saved code and only people with edit access can open it, so it is for testing only.
What is the other way? (Method 2: the official Google Sheets API)
The official route is the Google Sheets API v4. You read a range with GET https://sheets.googleapis.com/v4/spreadsheets/{spreadsheetId}/values/{range}, as the reference page shows. The reference lists OAuth scopes such as spreadsheets.readonly as the requirement.
For files shared with "Anyone on the Internet with this link," Google's credentials guide says an API key can be used to access publicly available data anonymously. You create it in the Google Cloud console under APIs & Services > Credentials > Create credentials > API key. Google asks you to check that the API you want supports keys, so test it with a public file first.
This method suits you when a backend service already speaks Google APIs, or when you need exact control over ranges and formatting. It does not give you a friendly JSON shape: you get arrays of values, and you map the headers yourself.
Is there a no-code option? (Method 3: SheetDB or Sheety)
Paid wrapper services connect to your sheet and give you a ready-made REST API. Two examples, with pricing as of 13 October 2026 from their own pricing pages:
| Service | Free tier | First paid plan |
|---|---|---|
| SheetDB | 2 spreadsheet APIs, 500 requests per month | $29.99 per month listed: 5 APIs, 10,000 requests per month |
| Sheety | 200 requests per month, 100 rows per sheet | $9.99 per month: 50,000 requests, 1,000 rows per sheet |
SheetDB says that at 100% of your quota requests are not executed and return a 429 error, and that limits reset on the 1st of each month at midnight UTC. These are the companies' own claims. Check current prices before you commit.
Which method should you choose?
Pick Apps Script for small, free projects where you want control. Pick the Sheets API if your code already uses Google credentials. Pick a wrapper if you want zero code and accept a monthly fee.
| Method | Cost | Difficulty | Limits | Best for |
|---|---|---|---|---|
| Apps Script web app | Free | Medium (paste code) | 6 min per run, 30 simultaneous runs per user | Prototypes, internal tools, forms |
| Google Sheets API v4 | Free within quota | Higher (credentials) | 300 reads and 300 writes per minute per project | Backend services |
| SheetDB or Sheety | Free tier, then from $9.99 to $29.99 per month | Low | 200 to 500 requests per month free | Non-coders |
What's free and what costs money?
Method 1 costs nothing. As of 13 October 2026, Google's Apps Script quotas page lists 6 minutes per execution, 30 simultaneous executions per user and 1,000 per script, for both consumer and Workspace accounts. Quotas are per user and reset 24 hours after the first request.
For the Sheets API, Google lists 300 read and 300 write requests per minute per project, and 60 per minute per user per project. Going over returns a 429: Too many requests error and you can retry after a minute. Google recommends exponential backoff. The same page says that exceeding the quota limits is planned to incur charges to your Google Cloud billing account later in 2026, so check the page if you expect heavy traffic.
What can go wrong, and how do you fix it?
| Problem | Likely cause | Fix |
|---|---|---|
| You see a Google sign-in page instead of JSON | Access is not set to anonymous | Edit the deployment and change Who has access |
| Your change does not appear | You saved but did not deploy a new version | Deploy > Manage deployments > Edit, pick a new version |
unauthorized in the response | Key missing or wrong | Add ?key= or the key field with your exact key |
| Rows land in the wrong order or collide | Two writes at once | The code above uses LockService.getScriptLock() to stop concurrent runs, as Google describes |
| HTTP 405 error | A parameter named c or sid | Google reserves these names; rename them |
| Quota or timeout errors | Too many calls or a script over 6 minutes | Cache results, batch writes, or move to a database |
One more trap: appendRow treats a value starting with = as a formula. That is why the sample code blanks such values. Without it, a caller could inject formulas into your sheet.
Is this allowed, and is it safe?
It is allowed. Apps Script web apps are a documented Google feature. The risk is exposure, not rules.
With Execute the app as me and anonymous access, anyone with the URL runs your script with your permissions. The API key check in the code is a simple gate, not strong security. It sits in a URL for reads, so it can end up in browser history and logs. Keep private data out of the sheet.
If you only want to share a read-only copy, File > Share > Publish to web is simpler. Google warns to be careful when publishing private or sensitive info, and says viewers can see cell values but not formulas.
Related: if you want rows to arrive in a sheet from another source, read how to log Gmail messages into Google Sheets.
What's still unclear?
- Dropdown labels. Google's guide does not list the exact wording of the Who has access options in the deploy dialog, so labels may differ from what you see.
- API keys on the Sheets API. Google's general credentials page describes API keys for public files, but the Sheets reference page lists only OAuth scopes.
- Browser calls from other sites. Google's web app guide does not cover cross-origin (CORS) behavior. If your front end runs on another domain, test early or call the script from your own server.
- The weak point of the whole idea. A sheet is not a database. It has no indexes and small quotas, so this approach fits small, low-traffic tools.
Last checked: 13 October 2026.
Frequently asked questions
Can I use a Google Sheet as a database for my app?
For small projects, yes. A Sheet works well for a few thousand rows that people also want to edit by hand. It has no indexes and no real transactions, and Apps Script limits each run to 6 minutes. If your app needs fast queries, many users writing at once, or private data at scale, use a real database instead.
Is an Apps Script web app free?
Yes. Apps Script is included with a Google account at no extra charge. You are limited by quotas: Google's quota page lists 6 minutes per execution and 30 simultaneous executions per user, the same for consumer and Workspace accounts as of 13 October 2026. Workspace accounts get higher daily limits for some services.
Why does my API call return HTML instead of JSON?
Usually the script returned an error page, or the deployment access setting forced a Google sign-in page. Open the URL in a private window. If you see a sign-in screen, the deployment is not open to anonymous users. If you see an error, check the Executions log in the Apps Script editor.
Do I need to redeploy after changing my script?
Yes. Google's deployment docs say that to ship a code change you create a new version and edit the deployment to use it. The /exec URL stays the same. The /dev test URL always runs your latest saved code, but only people with edit access can open it.
Is it safe to make a Google Sheet API public?
Only if the sheet holds nothing private. Anyone who has the URL can call a public web app. Add a secret key check in the script, never put passwords or personal data in the sheet, and keep write access behind that key.
What is the difference between the Apps Script method and the Google Sheets API?
Apps Script lets you design your own endpoint and return exactly the JSON you want, with no Google Cloud project. The Google Sheets API v4 is Google's official REST interface. It needs OAuth credentials (or an API key for public files) and has a quota of 300 read requests per minute per project.
Sources
- Web apps | Apps Script, Google for Developers (2026-09-03)
- Deployments | Apps Script, Google for Developers (2026-09-15)
- Quotas for Google Services | Apps Script, Google for Developers (2026-09-03)
- Class ContentService | Apps Script, Google for Developers (2026-10-13)
- Class Sheet | Apps Script, Google for Developers (2026-10-13)
- Class LockService | Apps Script, Google for Developers (2026-10-13)
- Usage limits | Google Sheets API, Google for Developers (2026-09-03)
- Method: spreadsheets.values.get, Google for Developers (2026-06-16)
- Create access credentials | Google Workspace, Google for Developers (2026-09-03)
- Publish to the web | Google Docs Editors Help, Google (2026-10-13)
- SheetDB pricing, SheetDB (2026-10-13)
- Sheety pricing, Sheety (2026-10-13)
- How to Handle GET and POST HTTP Requests in Google Apps Script, Digital Inspiration (2026-10-13)