この記事はand factory.inc Advent Calendar 2025 8日目の記事です。
前回の記事は @yasukotelin さんの Androidプロジェクトの CI で役立つメモリ設定テクニック でした ![]()
今年に入りコーディング絵0ジェントが登場し、簡単にツールが構築できる時代になりました。
この記事では社内ツールをGASで提供するメリットとデメリットといくつかのTipsを紹介します。
社内ツールをGASで提供するメリット
claspを利用して開発することで、CLIツールを用いてコーディングからデプロイまで一貫して行うことができる
claspを用いてローカル環境でツール開発を行い、かつそれをコマンドで容易にGAS環境にデプロイすることが可能です。
要求を整理してAIに依頼すれば環境構築からデプロイまでほぼお任せ可能。
GoogleWorkspaceの所属組織に対してアクセス許可が設定できる
アクセス可能なユーザーを共有設定やデプロイ時のアクセスユーザー権限により行えるため、社内メンバーのみアクセスできるツールを簡単に提供できます
スプレッドシートと連携することで比較的容易にデータ管理ができる
GASはGoogleスプレッドシートとシームレスに連携できるため、専用のデータベースを用意することなくデータ管理機能を実装できます。
Webアプリの作成を容易に行うことができる
近年のAIモデルでは簡単な要件であればUIについて細かな指定なしでもいい感じにWebページの作成が可能です。
スプレッドシートのデータを軸に取り扱うのであればLooker StudioでBIツールを構築するよりも依頼してしまったほうが描画が早くて見やすいことすらあります。
(ただし処理が正しいかについてはきちんと確認しましょう
Opus4.5に作ってもらったサンプル
prompt
---
# 問い合わせ対応ダッシュボードの作成
## 概要
カスタマーサポートやヘルプデスクの対応状況を可視化するダッシュボードをGASで作成してください。
## データソース
スプレッドシートの「問い合わせ一覧」シートに以下のカラムがあります。
- チケットID
- 受付日時
- カテゴリ(製品について / 料金について / 技術サポート / その他)
- ステータス(未対応 / 対応中 / 完了)
- 担当者
- 完了日時
## 表示する指標
1. ステータス別のチケット数
- 未対応 / 対応中 / 完了 の件数をカード形式で表示
2. カテゴリ別の問い合わせ割合
- 円グラフで表示
3. 平均対応時間
- 受付日時から完了日時までの平均時間を算出
4. 担当者別の対応件数
- 棒グラフで表示
| sheet | web |
|---|---|
![]() |
![]() |
社内ツールをGASで提供するデメリット
複雑なツールの提供には向かない
GASには1度の実行に対して上限時間が設定されているため、タイムアウトするような複雑な処理には向きません。
また、同時実行数にも制限があるため、一度に大量のアクセスが行われた場合エラーになる可能性があります。
小規模ツールとしての活用に留めるのが望ましいでしょう。
野良GASの乱立を招きやすい
誰にでも簡単に作成できてしまうため、管理者が把握していない野良GASが乱立してしまうリスクがあります。
似たようなGASがすでに存在しているにも関わらず再開発してしまったり、取り扱っている情報に対して正しくアクセス制限が行われないなどの問題も発生する可能性があります。
GASを使う際のガバナンスが整理されるのが望ましいです。
Tips
deploymentIdを固定することでWebページのURLを固定したまま更新する
GAS上にWebアプリを作成した場合、利用者は同じURLでツールにアクセスし続けることができるのが望ましいです。
claspのデプロイコマンドにオプションをつけることで一度公開したURLを維持したまま更新を反映することができます
# 新規でdelpoyされてしまうためURLが変わってしまう
clasp deploy
# 指定したdeployを更新するので、URLを維持したまま更新が可能
clasp deploy --deplpymentId AKfycbxXXXXXXXXXXXXXXXXXXXXXXXXXX
npmスクリプトでdeploymentIdを管理し、デプロイを自動化する
前述の--deploymentIdオプションを毎回追加するのは手間がかかりますし、IDの取り間違いのリスクもあります。npmのスクリプト機能を活用することで一度設定したdeploymentIdを使い続けることが可能です。
セットアップ手順
1. プロジェクトの初期化
まず、claspプロジェクトのディレクトリでnpmを初期化します。
npm init -y
2. claspのインストール
claspをプロジェクトの開発依存関係としてインストールします。グローバルインストールでも動作しますが、プロジェクトごとにバージョンを固定できるためローカルインストールを推奨します。
npm install --save-dev @google/clasp
3. package.jsonにdeploymentIdとスクリプトを設定
package.jsonを編集し、deploymentIdの管理とデプロイスクリプトを追加します。
{
"name": "my-gas-tool",
"version": "1.0.0",
"config": {
"deploymentId": "AKfycbxXXXXXXXXXXXXXXXXXXXXXXXXXX"
},
"scripts": {
"push": "clasp push",
"deploy": "clasp deploy --deploymentId $npm_package_config_deploymentId",
"release": "npm run push && npm run deploy"
},
"devDependencies": {
"@google/clasp": "^3.0.0"
}
}
4. 初回デプロイでdeploymentIdを取得
初めてデプロイする場合は、まずdeploymentIdを取得する必要があります。
# 初回デプロイ
clasp deploy
実行すると以下のような出力が得られます。
Deployed AKfycbxXXXXXXXXXXXXXXXXXXXXXXXXXX @1
このAKfycbx...の部分がdeploymentIdです。これをpackage.jsonのconfig.deploymentIdに設定します。
...
"config": {
"deploymentId": "AKfycbxXXXXXXXXXXXXXXXXXXXXXXXXXX" <- ここ
},
...
5. 以降のデプロイ
設定完了後は、以下のコマンドだけで同じURLを維持したままデプロイできます。
npm run deploy
今回のサンプルでは
npm run release
とすることでPushと合わせてURLを維持したままのデプロイが可能です。
アクセス範囲を組織に絞った際に発生するCORSエラー対応
Webアプリのアクセス範囲を「組織内の全員」に絞ると、外部からのfetchリクエストでCORSエラーが発生することがあります。
エラーの例
Access to fetch at 'https://script.google.com/macros/s/xxx/exec'
from origin 'null' has been blocked by CORS policy
対応方法:google.script.runを使用する
GASが提供するHtmlService内では、fetchの代わりにgoogle.script.runを使用することでCORSの問題を回避できます。google.script.runはGASのフロントエンド(HTML)とバックエンド(GAS)間の通信専用APIであり、同一オリジンとして扱われるためCORSの制約を受けません。
スプレッドシートからユーザー一覧を取得するコードサンプル
バックエンド(Code.gs)
// Webアプリのエントリーポイント
function doGet(e) {
// APIとして呼ばれた場合はJSONを返す
if (e.parameter.api === 'getUsers') {
const users = getUsers();
return ContentService
.createTextOutput(JSON.stringify(users))
.setMimeType(ContentService.MimeType.JSON);
}
// 通常アクセスはHTMLを返す
return HtmlService.createHtmlOutputFromFile('index');
}
// ユーザー一覧を取得する関数(fetch / google.script.run 共通で使用)
function getUsers() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('ユーザー');
const data = sheet.getDataRange().getValues();
const headers = data[0];
return data.slice(1).map(row => ({
id: row[0],
name: row[1],
department: row[2]
}));
}
フロントエンド(index.html)
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<h1>ユーザー一覧</h1>
<div id="result"></div>
<script>
// ============================================
// 方法1: fetchを使用(CORSエラーが発生する可能性あり)
// ============================================
function fetchUsers() {
const url = 'https://script.google.com/macros/s/xxxxx/exec?api=getUsers';
fetch(url)
.then(response => response.json())
.then(users => displayUsers(users))
.catch(error => console.error('fetchエラー:', error));
}
// ============================================
// 方法2: google.script.runを使用(推奨)
// ============================================
function loadUsers() {
google.script.run
.withSuccessHandler(users => displayUsers(users))
.withFailureHandler(error => console.error('エラー:', error))
.getUsers(); // Code.gsのgetUsers関数を呼び出し
}
// 共通の表示処理
function displayUsers(users) {
const html = users.map(user =>
`<p>${user.name}(${user.department})</p>`
).join('');
document.getElementById('result').innerHTML = html;
}
// ページ読み込み時に実行(google.script.runを使用)
document.addEventListener('DOMContentLoaded', loadUsers);
</script>
</body>
</html>
このサンプルでは fetch , google.script.run ともに最終的には Code.gs / getUsers() を呼び出しますが、fetch を利用している場合はうまく処理できずにCORSが発生します
まとめ
社内ツールの構築にはDifyやn8nなどの選択肢もありますが、自然言語ベースで大部分の実装が完了するコーディングエージェントとの親和性の高さや実現できることの幅から、GASも選択肢としては有力だと考えています。
「ちょっと業務改善してみよっかな!」と思ったら、ぜひ挑戦してみてください。

