A Google Site is a container. It shows things beautifully and it runs
no code of yours — no server, no database, no custom JavaScript on the page itself.
That single fact is the whole lesson. Everything dynamic you have ever seen on a Google Site
is a second machine — an Apps Script Web App, or an embedded page — showing
through a window in the Site.
谷歌网站是一个容器。它把内容展示得很漂亮,但它不运行你写的任何代码——没有服务器、没有数据库,页面本身也不跑你的 JavaScript。这一个事实就是整堂课的重点。你在谷歌网站上见过的所有动态效果,都是第二台机器——一个应用脚本网络应用,或者一个被嵌入的页面——透过窗口显示出来的。กูเกิลไซต์คือภาชนะ มันแสดงเนื้อหาได้สวยงาม แต่มันไม่รันโค้ดของคุณเลย ไม่มีเซิร์ฟเวอร์ ไม่มีฐานข้อมูล และไม่รัน JavaScript ของคุณบนหน้าเว็บนั้นเอง ข้อเท็จจริงข้อเดียวนี้คือแก่นของบทเรียนทั้งหมด ทุกสิ่งที่เคลื่อนไหวได้ซึ่งคุณเคยเห็นบนกูเกิลไซต์ ล้วนเป็นเครื่องที่สอง คือเว็บแอปแอปส์สคริปต์ หรือหน้าเว็บที่ถูกฝังไว้ ซึ่งแสดงผลผ่านหน้าต่างบานหนึ่ง
This lab builds both machines, wires them together with a Google Sheet as the
database, and then puts the whole thing under version control so it deploys from GitHub.
这个实验室会把两台机器都搭起来,用一个谷歌表格当数据库把它们连在一起,然后把整套东西纳入版本控制,让它可以从 GitHub 部署。แล็บนี้จะสร้างทั้งสองเครื่อง เชื่อมเข้าด้วยกันโดยใช้กูเกิลชีตเป็นฐานข้อมูล จากนั้นนำทั้งหมดเข้าสู่ระบบควบคุมเวอร์ชัน เพื่อให้ดีพลอยจากกิตฮับได้
The two machines. Whenever something does not work, ask first:
which machine is this supposed to run on? Nearly every beginner problem with Google
Sites is code written on the machine that cannot run it.
两台机器。每当有东西跑不起来时,先问一句:这段东西本来应该在哪台机器上运行?初学者在谷歌网站上遇到的问题,几乎都是把代码写在了跑不动它的那台机器上。สองเครื่อง เวลามีอะไรไม่ทำงาน ให้ถามก่อนว่า สิ่งนี้ควรรันบนเครื่องไหน ปัญหาของมือใหม่บนกูเกิลไซต์เกือบทั้งหมด คือการเขียนโค้ดไว้บนเครื่องที่รันมันไม่ได้
🔤 The words you need
Twenty words. Learn these first and the rest of the lab reads like plain English. Tap a card to hear it, or open it for the longer story.
二十个词。先把这些学会,实验室后面的内容读起来就像大白话。点卡片可以听发音,展开可以看更详细的解释。ยี่สิบคำ เรียนคำเหล่านี้ก่อน แล้วเนื้อหาที่เหลือจะอ่านง่ายขึ้นมาก แตะการ์ดเพื่อฟังเสียง หรือกดเปิดเพื่ออ่านคำอธิบายแบบยาว
Part 1 — Build a website with a real backend
1. The Words You Need (Glossary)
Learn the words first, or every later step will feel like guessing.
Architecturally, a dynamic Google Site is composed of two distinct "machines" working in tandem. Google Sites serves as the content delivery platform—it is a secure, responsive container for text, images, and media. However, Sites cannot execute custom server-side code.
Apps Script serves as the backend logic engine. It performs the heavy lifting, such as querying a database (Google Sheets) or processing logic, and then serves the result into the Site. Because of the Iframe security boundary, the backend logic is sandboxed within the Site; it runs on Google's servers and is projected into the Site container.
Google Sites vs. Apps Script Web Apps
What each machine can do, and what it will never do.
Add text, images, and content blocks; embed Drive files, YouTube videos, and maps; manage site-wide navigation.
Design custom HTML UIs; automate tasks (emails/invites); access Service APIs (Gmail, Sheets); process custom data.
Limitations
No custom server-side code on-page; restricted to predefined layouts and standard widgets.
Requires formal deployment/versioning; necessitates authorization for private data; subject to Google Service quotas.
The "Talk-To" Relationship: The Site acts as the host and visual frame. The Web App acts as a service provider. When the Site loads, it requests the Web App URL via an iframe, triggering the script to execute and serve the dynamic content.
3. Build the Front: Setting Up Your Site
Create the site, add pages, add text and pictures. No code yet.
For Docs, Sheets, or Slides: Scroll to the bottom of the menu, select the file type, choose your file, and click Insert.
For Media/Widgets: Use the specific menu items for YouTube, Calendar, or Map to insert interactive content.
Architect's Pro-Tip: Sharing Permissions Simply embedding a file does not grant access to your visitors. If a file is restricted, visitors will see a 404 or "Access Denied" error. To ensure visibility: 1. Set the Drive file sharing to "Anyone with the link" as a viewer. 2. For maximum compatibility, use the File > Share > Publish to the web option within the specific Doc or Sheet before embedding the provided link in your site.
5. Build the Back: Creating the Web App
Write doGet, then deploy. Saving alone changes nothing for visitors.
Critical: You must use createTemplateFromFile().evaluate() to process any dynamic scriptlets (<?= ?>) in your HTML.
function doGet(e) {
// Generate a template and evaluate it to run server-side scriptlets
return HtmlService.createTemplateFromFile('Index').evaluate();
}
// Function to be called by the HTML template to retrieve data
function getSheetData() {
const sheetId = 'YOUR_SHEET_ID_HERE';
return SpreadsheetApp.openById(sheetId).getActiveSheet().getDataRange().getValues();
}
New Deployment Settings
Execute as and Who has access. Get these two wrong and nothing works.
Execute as: Select Me. This is vital for "Database" access; it allows the app to read your private Google Sheet even if the site visitor does not have access to that Sheet.
Who has access: Select Anyone to allow the Site iframe to load the content for all visitors.
6. The Database: Google Sheets Integration
A spreadsheet is a perfectly good database for a small site.
// Read Logic: Retrieves the entire sheet as a 2D array
function readData(sheetId) {
const data = SpreadsheetApp.openById(sheetId).getActiveSheet().getDataRange().getValues();
return data; // Result: [[Row1Col1, Row1Col2], [Row2Col1, Row2Col2]]
}
// Write Logic: Appends a new data row to the bottom
function appendData(sheetId, newRowArray) {
const sheet = SpreadsheetApp.openById(sheetId).getActiveSheet();
sheet.appendRow(newRowArray); // e.g., ['2023-10-27', 'User Submission']
}
7. Wire Them Together: The Embed
Paste the Web App URL into the Site. This is the moment it becomes one website.
Apps Script identifies needed permissions by scanning your code for service calls (e.g., SpreadsheetApp).
User Prompt: When you first run or deploy the script, an "Authorization required" dialog appears.
Granular Consent: You must grant access to the specific scopes the script detected.
Unverified App Warning: If you see this screen, click Advanced and then Go to [Project Name] (unsafe) to proceed. This is standard for private scripts that haven't undergone Google's public verification process.
9. Publish: Going Live
Choose who can view it, then connect your own domain name.
To fully decommission your project, follow these specific steps:
Unpublish the Site: Click the drop-down next to "Publish" and select Unpublish.
Undeploy the Web App: In the Apps Script editor, go to Deploy > Manage deployments. Select the active deployment and click Archive or Remove to stop the URL from resolving.
Delete Files: Use the "More" (three dots) menu on the Google Sites home screen to Remove the site. In the Apps Script dashboard, move the project to the trash.
11. Ten Things That Will Go Wrong (Troubleshooting)
Symptom, cause, fix. Read this before you ask anyone for help.
the sources confirm that no public API, CLI, or Git-based method currently exists for programmatically writing content directly into native Google Sites elements.
The Core Constraint
Google Sites is strictly a manual, browser-based builder. The consequence of this architecture is that the "shell" of your site—its navigation, page hierarchy, and native text/image blocks—cannot be deployed or modified via a repository.
Warning: The Site itself must be constructed and structured by hand in the browser at sites.google.com/new. Automation is reserved for the components you embed within this manual shell.
2. The Hybrid Architecture: What IS Deployable
You cannot deploy the Site, but you can deploy both things it displays.
GitHub Pages serves as our automated hosting layer. A significant advantage here is that GitHub Pages supports over 750 MIME types, allowing you to serve specialized file extensions that the native Google Sites platform might otherwise block or misinterpret.
Step-by-Step Instructions
Create a Repository: Initialize a repository on GitHub.
Add Entry Point: Create an index.html file in the root directory.
Configure Settings: Navigate to Settings > Pages.
Select Source: Under "Build and deployment," click the "Source" dropdown. Explicitly select "GitHub Actions" (do not use the default "Deploy from a branch" if you intend to use the workflow below).
Workflow Configuration
Create .github/workflows/deploy.yml to publish on every push to main:
Once the frontend is live, integrate it into your manual shell.
Integration Steps
Open your site in the Google Sites editor.
Click Insert > Embed.
Select By URL and paste your GitHub Pages URL.
Full Page Embed
For a seamless, "native" application feel, use a Full Page Embed:
Click the Pages tab.
Hover over Add (+) and select Full page embed.
Paste the URL and click Insert.
Synchronization Clarity
While the embedded content updates automatically when the GitHub Pages site changes, Google documentation for "Add a page or section of content from another website" requires a final manual step for the public to see changes to the Site shell: At the top right, click Publish. If changes do not appear, you must republish or refresh the Site to ensure the shell is indexed correctly.
5. Track B: Deploying the Backend with clasp
clasp turns the browser-only script editor into ordinary files in a repo.
To manage logic (emails, database triggers, or Workspace automation) via GitHub, use the Command Line Apps Script Projects (clasp) tool.
Hard Truth: Clasp 3.x TypeScript Limitation
Note that Clasp 3.x no longer transpiles TypeScript code. If your project uses TypeScript, you must use a bundler like Rollup or a template like wildh0g/apps-script-engine-template to transform code before pushing.
Local Setup
Install:npm install -g @google/clasp.
Enable API: You must enable the Apps Script API at script.google.com/home/usersettings.
Login: Run clasp login.
Initialize: Run clasp create or clasp clone <Script ID>.
Required Files: Ensure .clasp.json (config) and appsscript.json (manifest) are in your repository. Use clasp push to upload and clasp deploy to version your code.
6. Automating Track B in GitHub Actions
Store the credential as a secret so the robot can log in without you.
6. 用 GitHub Actions 自动化路线 B — 把凭证存成 secret,机器人就能自己登录,不用你动手。
6. ทำเส้นทาง B ให้อัตโนมัติด้วยกิตฮับแอคชันส์ — เก็บข้อมูลรับรองไว้เป็น secret เพื่อให้ระบบล็อกอินเองได้โดยไม่ต้องรอคุณ
Headless CI requires secure credential management.
Headless CI Instructions
Secret Extraction: Your local clasp login creates a .clasprc.json file. This is the "Master Key" to your Google Script environment; handle it with extreme care.
GitHub Secret: Copy the contents of .clasprc.json and store it in GitHub Secrets as CLASPRC_JSON.
Warning: While ~/.clasprc.json is the standard convention for Linux runners, the provided Google/Clasp documentation does not explicitly confirm this path.
7. Keeping the Deployment URL Stable
Update the existing deployment. A new one gets a new URL and breaks your embed.
In Google Apps Script, creating a "new deployment" generates a new unique ID, which breaks existing embeds in Google Sites.
Actionable Step: To ensure the Site embed remains stable, do not create a new ID. Instead, update the existing deployment ID with your new code version using:
clasp update-deployment <deploymentId>
8. Git Governance: What to Commit and What to Ignore
Credentials never go in git. Not once, not privately, not for a minute.
Google Sites cannot be fully deployed via Git; the site shell is a manual, browser-based construct.
Use GitHub Pages to bypass Google Sites' native file restrictions and serve custom code.
The Apps Script API must be toggled "On" in your Google user settings for clasp to function.
Never commit .clasprc.json; it grants full access to your Google Script environment.
Google Sites requires you to click "Publish" to reflect structural or indexing changes.
Use clasp update-deployment to maintain stable URLs and avoid breaking Site embeds.
GitHub Pages allows you to serve 750+ MIME types, bypassing native Google Sites file restrictions.
Clasp 3.x does not transpile TypeScript; use a separate bundler like Rollup for TS projects.
Addendum — clasp 2.x vs 3.x command names
Verified directly against the google/clasp README, because the
generated tutorials above mix the two generations. If a command “does not exist”,
you are almost certainly reading a 2.x tutorial while running a 3.x binary.
clasp 2.x
clasp 3.x
What it does
clasp deploy
clasp create-deployment
Create a NEW deployment (new ID — breaks your embed)
clasp deploy -i <id>
clasp update-deployment <id>
Update an EXISTING deployment (ID stays — embed keeps working)
clasp undeploy <id>
clasp delete-deployment <id>
Remove a deployment
clasp open
clasp open-script
Open the script in the browser editor
clasp open --web
clasp open-web-app
Open the deployed web app
clasp apis enable <api>
clasp enable-api <api>
Enable an advanced service
clasp logs --open
clasp open-logs
Open Cloud logs
Verified. The README states that other commands were also renamed
but retain aliases for compatibility — which is why clasp deploy often
still appears to work on 3.x, and why mixed tutorials survive in the wild.
The one that actually bites.create-deployment mints a
new deployment ID, and your Google Site embed still points at the old URL. The page
keeps serving stale code and nothing errors. To ship a change to a live embed you want
update-deployment <id>, every time.
clasp 3.x dropped TypeScript transpiling. If your repo is TypeScript
you must bundle first (Rollup, or a template such as WildH0g/apps-script-engine-template)
and push the compiled output.
Where this came from
Both tutorials above were generated by NotebookLM from 22 primary sources —
Google’s own Apps Script guides, the Google Sites Help Center, GitHub’s Pages and
Actions docs, and the google/clasp README. Nothing was written from memory.
Honesty notes carried through from the sources. Where the sources did
not confirm something, the tutorials say so instead of guessing — specifically the
“Who has access” option names, and the exact ~/.clasprc.json
path on a CI runner.
There is no git push to a Google Site. New Google Sites
exposes no public write API; the old Sites API covered Classic Sites only. The Site shell is
always built by hand. What you deploy from GitHub are the two things the Site displays.