Shared chat
Create Google Sheets PWA
Great use case — you can do this with Google Apps Script as the backend (writes rows to your Sheet, saves photos to Drive) and a simple PWA frontend (installable, works on a phone camera). Here's a complete working setup.
Architecture
- Google Sheet = your database (columns: Timestamp, VIN, Service, Price, VIN Photo URL, Vehicle Photo URL)
- Apps Script Web App = API that receives form data + photos, saves photos to a Drive folder, appends a row
- PWA = HTML form with camera/photo inputs, service dropdown with auto-price, manifest + service worker so it installs like an app
1. Apps Script backend (Code.gs)
In your Sheet: Extensions → Apps Script, paste this:
Then: Deploy → New deployment → Web app → Execute as Me, access Anyone. Copy the web app URL.
2. PWA frontend (index.html)
Host this on GitHub Pages, Netlify, or Vercel (free — PWAs need HTTPS):
3. PWA files
manifest.json:
sw.js:
Setup checklist
- Create a Drive folder for photos → copy its ID into
FOLDER_ID - Paste
Code.gsinto Apps Script → deploy as web app → copy URL intoAPI_URL - Upload the 3 frontend files + two icon PNGs to GitHub Pages/Netlify
- Open on your phone → "Add to Home Screen" → it installs as an app
Notes:
capture="environment"opens the rear camera directly on phones — perfect for VIN shots.- Photos are compressed to ~1280px JPEG before upload to keep things fast.
- Want offline queueing (save entries with no signal, sync later)? That's an IndexedDB addition to the service worker — let me know and I'll extend it.
If you share your sheet's exact column headers, I'll adjust the appendRow order to match.
You have two places to do this — in the Google Sheet itself and in the app's list view. Here's both.
1. Show thumbnails in the Google Sheet
The trick: drive.google.com/uc?id=... links often don't render in Sheets' IMAGE() formula. Use Drive's thumbnail endpoint instead — it also gives you the reduced size for free:
Update saveImage() in your Apps Script to write an IMAGE() formula instead of a bare URL:
Then in doPost, write the formulas with setFormula instead of plain appendRow:
Tips:
sz=w200= 200px wide. Usew400for bigger,w100for smaller.IMAGE(url)defaults to "fit to cell," so the row height / column width controls display size.IMAGE(url, 4, 80, 80)forces an exact 80×80 px if you prefer.- Keeping the raw file IDs in columns G/H means your app doesn't have to parse formulas.
2. Show thumbnails in the PWA (list/gallery view)
If you add a list screen that reads from doGet(), render the IDs as <img> tags using the same thumbnail URL, with a click-through to the full image:
With a little CSS:
loading="lazy"keeps the list fast when you have many rows.- Tapping a thumbnail opens the full-resolution photo in Drive.
- Photos must be shared "Anyone with link" (your
setSharingcall already does this) or the thumbnails will show as broken images.
One caveat: if you have existing rows with the old uc?id= URLs, you can convert them once with a formula like:
Want me to add the full gallery/list screen to the PWA so you can browse and search past entries by VIN?
Most likely one of these is missing:
- Your Apps Script is saving photos to Drive but not appending the row
SHEET_NAMEdoes not match your actual Google Sheet tab name- The script is not connected to the correct spreadsheet
- You edited Apps Script but did not redeploy a new Web App version
- The PWA is using the wrong Apps Script URL
- The request is failing silently
The safest fix is to use the Spreadsheet ID directly instead of relying on getActiveSpreadsheet().
Use this Apps Script backend
In Apps Script, replace your backend with this version.
Change these 3 values:
Full code:
Important: get the correct Spreadsheet ID
Your Google Sheet URL looks like this:
Copy only the long ID between /d/ and /edit.
Example:
Important: SHEET_NAME means the bottom tab name
This is not the file name.
If your bottom tab says:
Then use:
If it says:
Then use:
Your frontend submit code should look like this
Make sure your PWA is sending data to the Apps Script URL.
Your service dropdown should use clean value names:
Critical step: redeploy after editing Apps Script
After changing the Apps Script code:
- Click Deploy
- Click Manage deployments
- Click the pencil/edit icon
- Under Version, choose New version
- Click Deploy
- Copy the Web App URL again if needed
Your PWA should use the URL ending in:
Not:
Example in your PWA:
How to check what is failing
In Apps Script:
- Open your Apps Script project
- Click Executions on the left
- Submit a test entry from the PWA
- Refresh Executions
- Open the latest run
If it failed, you will usually see one of these:
Wrong sheet tab name
Fix:
Wrong spreadsheet ID
Fix SPREADSHEET_ID.
Wrong Drive folder ID
Fix FOLDER_ID.
Permission issue
Redeploy the Web App as:
- Execute as: Me
- Who has access: Anyone
What should appear in the Sheet
The Sheet should generate rows like this:
Columns G and H will show actual reduced-size images, not just links.
Most likely issue in your case
If photos are uploading but the Sheet is blank, the most likely problem is this line from the older code:
That can fail or point to nothing if the script is not properly bound to the Sheet.
Use this instead:
That forces Apps Script to write to the exact Google Sheet you want.
If it gets stuck on “Saving…”, your button is being disabled, but the fetch() request is either failing or never reaching your success/reset code.
Most common causes:
- Apps Script URL is wrong or still using old deployment
- Apps Script permissions/deployment not set correctly
- JavaScript error after clicking Save
- CORS issue with Apps Script
- Photo file is too large
- Your code does not have a proper
catch/finallyblock to reset the button
Use this safer submit code.
Replace your submit button code with this
This is important because the finally section will always reset the button, even if saving fails.
If it still gets stuck, use this Apps Script-friendly version
Google Apps Script sometimes causes frontend CORS issues. If you see a CORS error in the browser console, change the fetch to this:
So the middle part becomes:
With mode: 'no-cors', the app can send the data, but it cannot read the response from Apps Script. So you will not get result.row, but the row should still be added to the Sheet.
Check these 5 things
1. Make sure your API URL ends in /exec
In your PWA:
Not:
Use /exec.
2. Open the API URL directly
Paste your Apps Script web app URL into your browser.
You should see something like:
If you get an authorization error, the deployment settings are wrong.
3. Redeploy Apps Script after every backend change
In Apps Script:
- Click Deploy
- Click Manage deployments
- Click the pencil/edit icon
- Choose New version
- Click Deploy
Make sure deployment is:
- Execute as: Me
- Who has access: Anyone
4. Check Apps Script executions
In Apps Script, click Executions on the left.
Then submit from your app.
If the request reached Apps Script, you should see a new execution.
If it failed, open it and look for the error.
Common errors:
Fix your SHEET_NAME.
Fix your FOLDER_ID.
Fix your SPREADSHEET_ID.
5. Make sure photos are compressed
If photos are too large, the upload may freeze or fail. Your compression function should be like this:
This keeps uploads much smaller.
Quick fix I would try first
Change your fetch() to this:
Then check the Google Sheet and Apps Script Executions.
If a row appears, the issue was the frontend trying to read the Apps Script response.
If it failed but nothing appears in Apps Script → Executions, then the request is not reaching your Apps Script web app at all.
So this is probably not a spreadsheet/write problem yet. It is one of these:
- Wrong
API_URL - Web app not deployed as
/exec - PWA is still using old cached JavaScript
- Button click code is failing before
fetch() - CORS/redirect issue
- Service worker is serving an old version of your app
Do these checks in order.
1. Make sure your URL is the Web App /exec URL
In your frontend:
It should not be:
And it should not be your Google Sheet URL.
2. Open the API URL directly in browser
Paste the API_URL directly into your browser.
If your Apps Script has this:
You should see:
If you do not see that, your deployment is the issue.
3. Redeploy correctly
In Apps Script:
- Click Deploy
- Click Manage deployments
- Click the pencil/edit icon
- Choose New version
- Set:
- Execute as:
Me - Who has access:
Anyone
- Execute as:
- Click Deploy
Then copy the Web App URL again.
Use that URL in your PWA.
4. Your PWA may be using an old cached version
Because this is a PWA, the service worker may be serving your old JavaScript even after you edit the file.
For testing, temporarily unregister the service worker.
Add this near the bottom of your index.html:
Then reload the app completely.
On your phone, you may also need to:
- Delete the PWA from home screen
- Clear browser cache/site data
- Reopen the site
- Re-add to home screen later
This is a very common reason it keeps saying “Saving…” with old code.
5. Add a visible debug message before fetch()
Replace your save handler temporarily with this simplified debug version:
Now test again.
What the alerts mean
If you do not see:
Then your button handler is not connected.
If you see:
but not:
Then your JavaScript is breaking before fetch().
If you see:
but still see no execution in Apps Script, then your API_URL or deployment is wrong, or the service worker is still serving old code.
6. Add a basic doPost test
Temporarily replace your Apps Script with this simple version:
Then redeploy as a new version.
Test from the PWA again.
If this works, you should see a row like:
Then we know the frontend is reaching Apps Script.
7. Add this test button to your HTML
This removes photos from the equation and tests only the connection.
Add this button:
Then add this JavaScript:
Click Test API.
If this does not create an Apps Script execution, the problem is definitely:
- wrong
API_URL - bad deployment settings
- cached frontend
- button JavaScript not running
8. Make sure your button is not submitting a form
If your button is inside a <form>, the page may be reloading before the upload completes.
Change the button to:
Not just:
This one small issue can cause “Saving…” problems.
9. Remove Content-Type: application/json if you added it
For Apps Script web apps, avoid this during testing:
Use this instead:
Or:
Do not add custom headers yet.
Most likely fix
Based on “failed but no errors shown in Executions,” I would first check these:
- Your PWA is still using an old cached version.
- Your
API_URLis not the/execdeployment URL. - Your Save button is inside a form and needs
type="button". - You edited Apps Script but did not redeploy as a new version.
Start by adding this:
Then unregister the service worker, redeploy Apps Script, and test with the simple doPost above.
That message means your Apps Script Web App URL is working, but Apps Script cannot find a function named:
When you open the Web App URL in a browser, Google runs doGet().
When your PWA submits data, Google runs doPost().
So you need both functions in your Apps Script.
Add this doGet() to your Apps Script
Paste this anywhere in your Apps Script file, outside of all other functions:
Then your Web App URL should show:
Make sure your file has this structure
Your Apps Script should look generally like this:
This simplified version only tests writing VIN/service/price to the Sheet. Once this works, you can add the photo logic back in.
Important: redeploy after adding doGet()
After adding the function:
- Click Save
- Click Deploy
- Click Manage deployments
- Click the pencil/edit icon
- Under Version, choose New version
- Click Deploy
- Open the Web App URL again
Your URL should end in:
If you still see the error
Check these things:
1. Function name must be exactly lowercase/camelcase
Correct:
Wrong:
Wrong:
Wrong:
2. doGet() cannot be inside another function
Wrong:
Correct:
3. Make sure you are editing the correct Apps Script project
Sometimes there are two script projects:
- one attached to the Google Sheet
- one standalone project
The Web App URL may point to a different project than the one you are editing.
To confirm, add this to your doGet():
Redeploy as a new version, then open the URL.
If you do not see:
then your Web App URL is from a different deployment/project.
Next step
First get the Web App URL to show:
Once that works, your PWA should be able to submit to doPost().
This is a shared TryAI chat. Sign in to start your own conversation.
Sign in to TryAI