Getting a new row in Google Sheets every time Scriptube finishes a transcript takes one webhook and one of two receivers: a Make scenario, or a small Google Apps Script web app. Both listen for the same event and payload; pick whichever fits your stack.
What you're wiring together
Scriptube fires batch.completed (and transcript.ready per item) to a URL you register. That URL needs to end up writing a row to a sheet. There's no native Scriptube-to-Sheets connector â see zapier-make-youtube-transcripts-webhooks for why â so both options below go through the raw webhook.
Option A: Make scenario
- Add a Webhooks > Custom webhook module, create a new hook, copy its URL.
- Register it with Scriptube:
curl -X POST https://scriptube.me/api/webhooks/register \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://hook.make.com/XXXXXXXXXXXXX",
"events": ["batch.completed"],
"secret": "a-dedicated-random-string-16-to-256-chars"
}'
- Add a function/code step that computes the HMAC-SHA256 signature over
{timestamp}.{raw body}with your secret and compares it to theX-Scriptube-Signatureheader â the same check covered in zapier-make-youtube-transcripts-webhooks. Route on a match with a Filter immediately after. - Add a Google Sheets > Add a Row module. Map columns from the payload:
data.batch_id,data.status,data.item_count,data.completed_count,data.failed_count, and the top-leveltimestamp.
That's the whole scenario â one trigger, one verification step, one Sheets write. Test it by submitting a batch with a matching external_id you can look for in the new row; if you set external_id at submit time, it's echoed back inside data on every webhook, which makes matching a sheet row to the request that created it trivial.
Option B: Apps Script web app (no third platform at all)
If you don't want to run this through Make, Google Apps Script can be the webhook receiver directly, bound to the sheet itself.
In the target Sheet, open Extensions > Apps Script and paste:
function doPost(e) {
const secret = 'a-dedicated-random-string-16-to-256-chars';
const timestamp = e.parameter.ts || e.parameters['X-Scriptube-Timestamp'];
// Apps Script doesn't expose request headers on doPost(e) directly;
// verify using the raw POST body and the header value your proxy/
// relay forwards as a query param or a wrapped field, per your setup.
const rawBody = e.postData.contents;
const payload = JSON.parse(rawBody);
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Transcripts');
sheet.appendRow([
new Date(),
payload.event,
payload.data.batch_id,
payload.data.status,
payload.data.item_count,
payload.data.completed_count,
payload.data.failed_count,
]);
return ContentService.createTextOutput(JSON.stringify({ ok: true }))
.setMimeType(ContentService.MimeType.JSON);
}
Deploy it as a web app (Deploy > New deployment > Web app, execute as yourself, access "Anyone") and copy the deployment URL. Register that URL with Scriptube exactly as in Option A.
Important limitation: Apps Script's doPost(e) does not give you direct access to inbound request headers, which is where X-Scriptube-Signature and X-Scriptube-Timestamp arrive. Without header access, you cannot verify the HMAC signature inside Apps Script alone, which means anyone who learns your deployment URL could append fake rows. For anything beyond a personal/low-stakes sheet, put a small relay in front of it â a Cloudflare Worker or similar â that verifies the signature and only forwards the body to Apps Script on success, or use the Make route in Option A instead, where the verification step is straightforward.
Which one to use
| Make scenario | Apps Script only | |
|---|---|---|
| Signature verification | Yes, in a function step | Not without a relay in front |
| Extra service needed | A Make account | None |
| Best for | Anything that should be verified, or that also needs branching/other actions | A quick personal log where the URL stays private |
Avoiding duplicate rows
A webhook can be delivered more than once in genuinely rare cases â a slow receiver that times out just as it finishes writing, for instance, can cause Scriptube's retry logic to attempt a redelivery before it hears back. Guard against a duplicate row by checking the batch_id before appending: in Make, add a Google Sheets > Search Rows module filtering on the batch id column, and only run Add a Row when nothing matches. In Apps Script, scan the sheet's batch id column with a short loop before calling appendRow. It's a few extra lines either way, and it's the difference between a sheet that's safe to leave unattended and one you have to periodically de-duplicate by hand.
Getting more than the summary into the sheet
The webhook payload for batch.completed carries counts, not transcript text. If you want the actual transcript in the sheet (or a linked Drive file), add a second step that calls the export endpoint once the webhook confirms the batch finished:
GET https://scriptube.me/api/v1/transcripts/{batch_id}/export?format=csv
Header: X-API-Key: YOUR_API_KEY
CSV exports paste cleanly into Sheets' own CSV import, or you can pull it as JSON and map fields into columns yourself â see youtube-transcript-to-excel-google-sheets for column-by-column guidance on the export schema, and how-to-export-youtube-transcripts-to-srt-vtt-txt if you need a different output format instead.
Keeping the sheet from growing forever
A webhook-driven sheet only ever appends â nothing deletes an old row automatically. If you're tracking a high-volume workflow (a batch per hour, say), plan for periodic archiving: move rows older than a set window to a separate "archive" tab on a schedule, rather than letting one tab grow until Sheets itself starts slowing down. This is a Sheets limitation, not a Scriptube one â the webhook delivery itself doesn't care how big the destination sheet gets.
Start with an API key: /ui/signup.